第二章 仓颉程序设计基础 示例代码

浙江传媒学院 · 仓颉面向对象程序设计 · 基于 CangStream 框架构建

示例程序
24 个
实例程序
7 个
代码合计
31 个

一、基础程序示例(例2.1 – 例2.4)

例2.1 Hello World

基本输出程序,使用 println 函数向控制台输出字符串。

package demo
main(): Int64 {
   println("hello! 仓颉")
   return 0
}

例2.2 仓颉字符组合

''使用元组表示"仓"和"颉"两个汉字的偏旁组成结构。''

package demo
main() {
    let cang = ("人", "㔾", "仓")
    let jie  = ("吉", "页", "颉")
    let greeting = "hello," + cang[2] + jie[2]
    println(greeting)
    println("'${cang[2]}' 由 '${cang[0]}' 和 '${cang[1]}' 组成")
    println("'${jie[2]}' 由 '${jie[0]}' 和 '${jie[1]}' 组成")
}

例2.3 交互式问候

从标准输入读取编程语言名称,并输出问候语。

package demo
import std.console.Console
main() {
    print("请输入您学习的编程语言名称:")
    let name = Console.stdIn.readln().getOrThrow()
    println("${name},你好!")
    return 0
}

例2.4 自定义类型 — Web 终端输出

使用仓颉扩展库自定义 MyHttpServer 类,实现 Web 终端问候程序。完整实现将在类编程与网络编程章节详细介绍。

package demo
class MyHttpServer {
    let fontName: String
    let content: String
    init(fontName: String, content: String) {
        this.fontName = fontName
        this.content = content
    }
    func start(): Unit {
        println("Web 服务器已启动")
        println("字体:${fontName}")
        println("内容:${content}")
    }
}
main(): Int64 {
    let app = MyHttpServer("黑体", "Hello 仓颉!")
    app.start()
    return 0
}

二、函数与类(例2.5)

例2.5(版本1) 用函数实现求两数最大值

定义 max 函数,通过 if-else 表达式比较并返回较大值。

package demo
func max(a: Int64, b: Int64): Int64 {
    if (a > b) {
        return a
    } else {
        return b
    }
}
main(): Int64 {
    let x = 1
    let y = 5
    let fmax = max(x, y)
    println("${x} 和 ${y} 相比,${fmax} 比较大")
    return 0
}

例2.5(版本2) 用类实现求两数最大值

定义 FindMax 类,将比较逻辑封装为成员方法。

package demo
class FindMax {
    public var x: Int64
    public var y: Int64
    FindMax(a: Int64, b: Int64) {
        this.x = a
        this.y = b
    }
    func max(): Int64 {
        if (x > y) { return x } else { return y }
    }
}
main(): Int64 {
    var abmax = FindMax(1, 5)
    let fmax = abmax.max()
    println("${abmax.x} 和 ${abmax.y} 相比,${fmax} 比较大")
    return 0
}

三、数值类型(例2.6 – 例2.10)

例2.6 进位计数制字面量

同一个数值 24 用二进制、八进制、十进制、十六进制四种形式表示。

package demo
main() {
    let bInt: Int64 = 0b0001_1000   // 二进制
    let oInt: Int64 = 0o30          // 八进制
    let dInt: Int64 = 24            // 十进制
    let hInt: Int64 = 0x18          // 十六进制
    println("bInt is ${bInt}")
    println("oInt is ${oInt}")
    println("dInt is ${dInt}")
    println("hInt is ${hInt}")
}

例2.7 整数类型字面量后缀

通过后缀 i8、u64、i32 明确指定整数字面量的类型。

package demo
main() {
    var x = 100i8
    var y = 0x10u64
    var z = 0o432i32
    println("x is ${x} with type Int8")
    println("y is ${y} with type UInt64")
    println("z is ${z} with type Int32")
}

例2.8 字符字节字面量

字符字节字面量以 b 开头,表示 UInt8 类型的 ASCII 值。

package demo
main() {
    var a = b'x'
    var b = b'\n'
    var c = b'\u{78}'
    println("a is ${a} with type UInt8")
    println("b is ${b} with type UInt8")
    println("c is ${c} with type UInt8")
}

例2.9 幂运算

仓颉使用 ** 运算符进行幂运算,左操作数为 Int64 时右操作数须为 UInt64。

package demo
main() {
    let p1 = 2 ** 3
    let p2 = 2 ** UInt64(3 ** 2)
    let p3 = 2.0 ** 3.0
    let p4 = 2.0 ** 3 ** 2
    let p5 = 2.0 ** 3.0 ** 2.0
    println("2的3次方是 ${p1}")
    println("2的3**2次方是 ${p2}")
    println("2.0的3.0次方是 ${p3}")
    println("2.0的3**2次方是 ${p4}")
    println("2.0的3.0**2.0次方是 ${p5}")
}

例2.10 浮点类型字面量

浮点字面量支持十进制和十六进制两种形式,十六进制须包含指数部分(p/P)。

package demo
main() {
    let a: Float32 = 3.14
    let b: Float32 = 2e3
    let c: Float32 = 2.4e-1
    let d: Float64 = .123e2
    let e: Float64 = 0x1.1p0
    let f: Float64 = 0x1p2
    let g: Float64 = 0x.2p4
    println("a= ${a}")
    println("b= ${b}")
    println("c= ${c}")
    println("d= ${d}")
    println("e= ${e}")
    println("f= ${f}")
    println("g= ${g}")
}

四、字符与字符串(例2.11 – 例2.15)

例2.11 Rune 字符类型 — Unicode 编码

''使用 Unicode 码点表示汉字,输出"浙江传媒学院"。''

package demo
main() {
    let a: Rune = r'\u{6D59}'
    let b: Rune = r'\u{6C5F}'
    let c: Rune = r'\u{4F20}'
    let d: Rune = r'\u{5A92}'
    let e: Rune = r'\u{5B66}'
    let f: Rune = r'\u{9662}'
    print(a); print(b); print(c)
    print(d); print(e); print(f)
}

例2.12 单行字符串字面量

字符串字面量可用单引号或双引号定义,支持转义字符。

package demo
main() {
    let s0 = "开始"
    let s1: String = ""
    let s2 = '你好,仓颉'
    let s3 = "\"你好,仓颉\""
    let s4 = '你好,仓颉\n'
    let s5 = "\'结束\'"
    println("s0= ${s0}")
    println("s1= ${s1}")
    println("s2= ${s2}")
    println("s3= ${s3}")
    println("s4= ${s4}")
    println("s5= ${s5}")
}

例2.13 字符串字面量赋值给 Byte 和 Rune

单字符 ASCII 字符串可隐式转换为 Byte 类型;单字符字符串可隐式转换为 Rune 类型。

package demo
main() {
    var b: Byte = "0"
    print(b)
    b = "1"
    print(b)
    var r: Rune = "0"
    print(r)
    r = "1"
    print(r)
}

例2.14 插值字符串

''使用 ${} 将表达式嵌入字符串,实现动态文本拼接。''

package demo
main() {
    let ch1 = "木"
    let ch2 = "林"
    let sentence = "${ch1}+${ch1}=${ch2}"
    println(sentence)
}

例2.15 字符串判等与拼接

字符串支持 == 判等和 + 拼接操作。

package demo
main() {
    let char1 = "日"
    let char2 = "月"
    let char3 = "木"
    let char4 = "木"
    let char5 = "明"
    let char6 = "林"
    let r1 = char1 == char2
    let r2 = char3 == char4
    let result = "双${char3}成${char6},${char1}${char2}为${char5}!"
    println(result)
    println("\"明\"字的左右结构相同?答案是:${r1}")
    println("\"林\"字的左右结构相同?答案是:${r2}")
}

五、元组类型(例2.16 – 例2.17)

例2.16 三元组字面量及元素访问

元组可组合不同类型的值,通过下标 t[index] 访问指定位置的元素。

package demo
main() {
    var ming = (1, "日月", "明")
    println(ming[0])   // 输出第一个元素:1
    println(ming[1])   // 输出第二个元素:"日月"
    println(ming[2])   // 输出第三个元素:"明"
}

例2.17 元组字面量解构赋值

使用元组字面量对等号右侧的元组进行解构,_ 表示忽略对应位置的值。

package demo
main() {
    var a: Int64
    var b: String
    var c: Unit
    var f = { => ((1, "abc"), ()) }
    ((a, b), c) = f()               // a=1, b="abc", c=()
    ((a, b), _) = ((2, "def"), 3.0) // a=2, b="def", 3.0 被忽略
    println(a)
    println(b)
    println(c)
}

六、数组类型(例2.18 – 例2.20)

例2.18 用 for-in 遍历数组

Array 是有序集合,可用 for-in 循环遍历所有元素。

package demo
main() {
    let arr = [25, 45, 90]
    for (i in arr) {
        println("The element is ${i}")
    }
}

例2.19 用 size 属性判断数组是否为空

size 属性返回数组元素个数,可用于判断数组是否为空。

package demo
main() {
    let arr = [25, 45, 90]
    if (arr.size == 0) {
        println("This is an empty array")
    } else {
        println("The size of array is ${arr.size}")
    }
}

例2.20 数组下标访问

通过下标 arr[index] 访问指定位置的元素,下标从 0 开始。

package demo
main() {
    let arr = [23, 21, 62]
    let a = arr[0]             // a == 23
    let b = arr[1]             // b == 21
    let c = arr[arr.size - 1]  // c == 62,最后一个元素
    println(a)
    println(b)
    println(c)
}

七、特殊类型(例2.21 – 例2.22)

例2.21 Unit 类型

Unit 类型只有一个值 (),用于只关心副作用而不关心返回值的场景。

package demo
main() {
    let c: Unit = ()
    func sayHello(): Unit {
        println("Hello, Cangjie!")
    }
    let result = sayHello()
    let u1: Unit = ()
    let u2: Unit = ()
    println(u1 == u2)  // true
    println(u1 != u2)  // false
    println(c)         // ()
    println(result)    // ()
}

例2.22 Nothing 类型

break、continue、return、throw 表达式的类型均为 Nothing,执行后其后的代码不会被执行。

package demo
func testReturn() {
    println("准备返回")
    return 42   // return 表达式类型是 Nothing
}
func testThrow() {
    throw Exception("发生错误!")  // throw 表达式类型是 Nothing
}
main() {
    let arr = [1, 2, 3, 4, 5]
    for (i in arr) {
        if (i == 2) { continue }
        if (i == 4) { break }
        println("当前元素: ${i}")
    }
    let result = testReturn()
    println("返回值是:${result}")
    testThrow()
    return 0
}

八、类型转换(例2.23 – 例2.24)

例2.23 十进制转十六进制

通过自定义 decimalToHex 函数实现十进制到十六进制的进位计数制转换。

package demo
func decimalToHex(num: UInt32): String {
    if (num == UInt32(0)) { return "0" }
    var result = ""
    var n = num
    let hexChars = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
    while (n > UInt32(0)) {
        let remainder = n % UInt32(16)
        result = hexChars[Int64(remainder)] + result
        n = n / UInt32(16)
    }
    return result
}
main() {
    println(decimalToHex(10))   // 输出:A
}

例2.24 Rune 与 UInt32 类型转换

Rune 与 UInt32 之间的转换基于 Unicode 标量值:UInt32(rune) 得到码点,Rune(uint32) 得到对应字符。

package demo
main() {
    let x: Rune = 'a'      // 'a' 的 Unicode 编码为 97
    let y: UInt32 = 65     // 65 对应字符 'A'
    let r1 = UInt32(x)     // Rune -> UInt32,结果为 97
    let r2 = Rune(y)       // UInt32 -> Rune,结果为 'A'
    println("The type of r1 is 'UInt32', and r1 = ${r1}")
    println("The type of r2 is 'Rune', and r2 = ${r2}")
}

九、实例程序(实例2-1 – 实例2-7)

实例2-1 判断闰年

读取用户输入的年份,根据闰年规则(能被4整除且不被100整除,或能被400整除)进行判断。

package demo
import std.env.*
import std.convert.*
main() {
    getStdOut().write("请输入年份:")
    let s = getStdIn().readln().getOrThrow()
    let year = Int32.parse(s)
    if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
        getStdOut().write("${year}是闰年\n")
    } else {
        getStdOut().write("${year}不是闰年\n")
    }
}

实例2-2 阶乘累加和

计算 1! + 2! + 3! + … + n! 的累加和。

package demo
import std.env.*
import std.convert.*
main() {
    getStdOut().write("请输入一个小于12的整数:")
    let s = getStdIn().readln().getOrThrow()
    let n = Int64.parse(s)
    var sum = 0
    var prod = 1
    for (i in 1..n+1) {
        prod = prod * i
        sum = sum + prod
    }
    getStdOut().write("1到${n}的阶乘和为${sum}\n")
}

实例2-3 九九乘法表

用嵌套 for-in 循环输出九九乘法表。

package demo
import std.env.*
import std.convert.*
main() {
    getStdOut().write("请输入一个小于10的整数:")
    let s = getStdIn().readln().getOrThrow()
    let n = Int64.parse(s)
    for (i in 1..n+1) {
        for (j in 1..i+1) {
            getStdOut().write("${i}*${j}=${i*j} ")
        }
        getStdOut().write("\n")
    }
}

实例2-4 判断素数

读取一个整数,使用试除法判断其是否为素数。

package demo
import std.env.*
import std.convert.*
main() {
    getStdOut().write("请输入一个整数:")
    let s = getStdIn().readln().getOrThrow()
    let n = Int64.parse(s)
    var flag = true
    if (n == 1) { flag = false }
    var i = 2
    while (i * i <= n) {
        if (n % i == 0) { flag = false; break }
        i++
    }
    if (flag) {
        getStdOut().write("${n}是素数\n")
    } else {
        getStdOut().write("${n}不是素数\n")
    }
}

实例2-5 字符串翻转

将字符串转为 Rune 数组后从尾到头输出,实现字符串翻转。

package demo
import std.env.*
main() {
    let s: String = "秋江楚雁宿沙洲"
    getStdOut().write("原字符串为    :${s}\n")
    let str = s.toRuneArray()
    getStdOut().write("翻转后字符串为:")
    var i = str.size - 1
    while (i >= 0) {
        getStdOut().write("${str[i]}")
        i--
    }
    getStdOut().write("\n")
}

实例2-6 最大公约数与最小公倍数

读取两个整数,分别求其最大公约数(辗转相减法)和最小公倍数。

package demo
import std.env.*
import std.convert.*
func gcd(a: Int64, b: Int64): Int64 {
    var t = a
    while (t >= 1) {
        if (a % t == 0 && b % t == 0) { break }
        t--
    }
    return t
}
func lcm(a: Int64, b: Int64): Int64 {
    return a * b / gcd(a, b)
}
main() {
    getStdOut().write("请输入第一个整数:")
    var s = getStdIn().readln().getOrThrow()
    let a = Int64.parse(s)
    getStdOut().write("请输入第二个整数:")
    s = getStdIn().readln().getOrThrow()
    let b = Int64.parse(s)
    getStdOut().write("${a}和${b}的最大公约数为${gcd(a,b)}\n")
    getStdOut().write("${a}和${b}的最小公倍数为${lcm(a,b)}\n")
}

实例2-7 输出汉字的 Unicode 编码

将汉字的 Unicode 标量值转换为十六进制,并以 U+ 前缀形式输出。

package demo
func decimalToHex(num: UInt32): String {
    if (num == UInt32(0)) { return "0" }
    var result = ""
    var n = num
    let hexChars = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
    while (n > UInt32(0)) {
        let remainder = n % UInt32(16)
        result = hexChars[Int64(remainder)] + result
        n = n / UInt32(16)
    }
    return result
}
func decimalToHexWithPrefix(num: UInt32): String {
    return "U+" + decimalToHex(num)
}
main() {
    let a = r'啊'
    println("汉字${a}的Unicode码是${decimalToHexWithPrefix(UInt32(a))}")
}