第七章 子类型关系和多态性 示例代码

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

示例程序
24 个
程序示例
5 个
代码合计
31 个

一、子类型关系(7.1)

7.1.1 子类型关系与子类型多态;7.1.2 子类型的判定(类继承、接口实现、函数类型、永远成立、传递性、类型别名)。本节为理论内容,无独立示例程序。

二、多态性(7.2)

例7-1 函数重载实现编译时多态

7.2.1:add 函数分别接受 Int64 和 Float64 参数,编译器根据实参类型选择对应版本。

package demo
// 函数重载示例
func add(a: Int64, b: Int64): Int64 {
    return a + b
}

func add(a: Float64, b: Float64): Float64 {
    return a + b
}

main() {
    let intResult = add(1, 2)          // 调用 Int64 类型的 add
    let floatResult = add(1.5, 2.5)    // 调用 Float64 类型的 add
    println("Int result: ${intResult}")
    println("Float result: ${floatResult}")
}

例7-2 通过继承类实现运行时多态

7.2.2:Animal → Dog/Cat,父类变量指向子类实例,运行时调用实际类型的 speak()。

package demo
// 定义父类 Animal
open class Animal {
    public open func speak() {
        println("动物叫声")
    }
}
// 定义子类 Dog 继承自 Animal
class Dog <: Animal {
    public override func speak() {
        println("汪汪")
    }
}
// 定义子类 Cat 继承自 Animal
class Cat <: Animal {
    public override func speak() {
        println("喵喵")
    }
}
main() {
    // 父类类型的变量可以指向子类实例
    let animal1: Animal = Dog()  // 通过父类引用指向子类实例 Dog
    let animal2: Animal = Cat()  // 通过父类引用指向子类实例 Cat
    animal1.speak()  // 输出: 汪汪 (实际调用 Dog 中的 speak)
    animal2.speak()  // 输出: 喵喵 (实际调用 Cat 中的 speak)
}

例7-3 通过继承接口实现运行时多态

7.2.2:Speaker 接口,Dog/Cat 实现 speak(),接口变量实现多态调用。

package demo
// 定义接口 Speaker
interface Speaker {
    func speak(): Unit
}
// 定义类 Dog 实现 Speaker 接口
class Dog <: Speaker {
    public func speak() {
        println("汪汪")
    }
}
// 定义类 Cat 实现 Speaker 接口
class Cat <: Speaker {
    public func speak() {
        println("喵喵")
    }
}
main() {
    // 父接口类型的变量可以指向子类实例
    let speaker1: Speaker = Dog()  // 通过接口引用指向子类实例 Dog
    let speaker2: Speaker = Cat()  // 通过接口引用指向子类实例 Cat
    speaker1.speak()  // 输出: 汪汪 (实际调用 Dog 中的 speak)
    speaker2.speak()  // 输出: 喵喵 (实际调用 Cat 中的 speak)
}

三、类型转换(7.3)

数值类型转换示例

7.3.1:Int8↔Int16、Float32↔Float64、整数↔浮点的显式转换。

package demo
main() {
    // 初始化整数类型变量
    let a: Int8 = 3
    let b: Int16 = 50   
    // 将 Int8 转换为 Int16
    let r1 = Int16(a)
    println("The type of r1 is 'Int16', and r1 = ${r1}")    
    // 将 Int16 转换为 Int8
    let r2 = Int8(b)
    println("The type of r2 is 'Int8', and r2 = ${r2}")    
    // 初始化浮点类型变量
    let c: Float32 = 1.0
    let d: Float64 = 1.123456789    
    // 将 Float32 转换为 Float64
    let r3 = Float64(c)
    println("The type of r3 is 'Float64', and r3 = ${r3}")    
    // 将 Float64 转换为 Float32
    let r4 = Float32(d)
    println("The type of r4 is 'Float32', and r4 = ${r4}")    
    // 将整数转换为浮点数
    let e: Int64 = 1024
    let f: Float64 = 1024.1024    
    // 将 Int64 转换为 Float64
    let r5 = Float64(e)
    println("The type of r5 is 'Float64', and r5 = ${r5}")    
    // 将 Float64 转换为 Int64
    let r6 = Int64(f)
    println("The type of r6 is 'Int64', and r6 = ${r6}")
}


Rune 与 UInt32 互转示例

7.3.1:Rune 字符与 UInt32 Unicode 标量值之间的相互转换。

package demo
main() {
    let x: Rune = 'a'      // 将字符 'a' 赋值给 x(Rune 类型)
    let y: UInt32 = 65     // 将整数 65 赋值给 y(UInt32 类型)
    
    let r1 = UInt32(x)     // 将 Rune 类型的 'a' 转换为对应的 Unicode 标量值 97
    let r2 = Rune(y)       // 将整数 65 转换为对应的字符 'A'
    
    println("The type of r1 is 'UInt32', and r1 = ${r1}") // 输出 r1 的类型和值
    println("The type of r2 is 'Rune', and r2 = ${r2}")   // 输出 r2 的类型和值
}

例7-4 is 操作符使用示例

7.3.2:用 is 检查变量的运行时类型,返回 Bool 结果。

package demo
main() {
    // 定义一些变量
    let a: Int64 = 10
    let b: Float64 = 3.14

    // 使用 is 操作符检查类型
    println("${a is Int64}")   // 输出 true
    println("${a is Float64}") // 输出 false
    println("${b is Float64}") // 输出 true
    println("${b is Int64}")   // 输出 false
}

例7-5 is 操作符程序分析示例

7.3.2:Base/Derived 类层次中 is 判断,展示父类变量指向子类实例时的类型检测。

package demo
open class Base {
    var name: String = " 仓颉编程语言"}
class Derived <: Base {
    var age: UInt8 = 3
}
main() {
    let a = 1 is Int64
    println("1是 'Int64'类型吗? ${a}")    
    let b = 1 is String
    println("1是'String'类型吗? ${b}")    
    let b1: Base = Base()
    let b2: Base = Derived()    
    var x = b1 is Base
    println("b1是'Base'类型? ${x}")    
    x = b1 is Derived
    println("b1是 'Derived'类型? ${x}")    
    x = b2 is Base
    println("b2是'Base'类型? ${x}")    
    x = b2 is Derived
    println("b2是'Derived'类型? ${x}")
}

例7-6 使用 as 操作符的示例

7.3.2:as 返回 Option 类型,用 match 处理转换成功/失败两种情况。

package demo
// 定义基类和派生类
open class Base {
    var name: String = "仓颉编程语言"
}
class Derived <: Base {
    var age: UInt8 = 5
}
main() {
    // 创建一个Base类型的对象,并将其转换为Derived类型
    let b1: Base = Derived()
    // 使用 as 操作符进行类型转换
    let result = b1 as Derived // 尝试将Base转换为Derived
    // 使用match语句判断转换是否成功
    match (result) {
        case Option.Some(d: Derived) => println("转换成功!${b1.name}${d.age}岁了!") // 转换成功
        case Option.None => println("转换失败!") // 转换失败
    }
    // 示例:试图将Base类型转换为String类型,肯定会失败
    let b2: Base = Base()
    let result2 = b2 as String // Base无法转换为String
    match (result2) {
        case Option.Some(s: String) => println("转换成功!字符串内容: ${s}")
        case Option.None => println("转换失败!无法将Base类型转换为String")
    }
}

例7-7 is 与 as 操作符配合使用

7.3.2:先用 is 判断类型,再用 as 安全转换,避免不必要的失败分支。

// ⚠ 无法读取文件: chapter07/demo7-9
// 错误: The file does not exist or permission denied!

四、泛型(7.4)

例7-8 泛型类 List 的计算

7.4:自定义 Option 和链表 List,sumInt 遍历链表求和。

package demo
// 定义 Option 类型
enum Option<T> {
    Some(T) |
    None
}

// 定义泛型类 List,T 为类型形参
class List<T> {
    var elem: Option<T>
    var tail: Option<List<T>>

    List(elem: T, tail: Option<List<T>>) {
        this.elem = Option.Some(elem)
        this.tail = tail
    }
}

// 定义一个函数 sumInt,它接受一个 List<Int64> 类型的参数
func sumInt(a: List<Int64>): Int64 {
    var sum: Int64 = 0
    var current = a
    // 遍历链表中的每个元素并计算总和
    while (true) {
        match (current.elem) {
          case  Option.Some(value) => sum += value
          case  Option.None => break // 不会发生,但如果有空值则退出
        }
        // 获取下一个节点
        match (current.tail) {
         case   Option.Some(next) => current = next
         case   Option.None => break // 没有尾部时结束
        }
    }
    return sum
}

main() {
    // 创建一个 List<Int64> 类型的链表
    let list1 = List<Int64>(1, Option.None)
    let list2 = List<Int64>(2, Option.Some(list1))
    let list3 = List<Int64>(3, Option.Some(list2))
    // 调用 sumInt 计算链表中的元素和
    let result = sumInt(list3)
    println("The sum of the list is: ${result}") // 输出:The sum of the list is: 6
}

例7-9 泛型函数示例(composition)

7.4.1:composition 复合两个函数,times2 和 plus10 组合后对输入先乘再加。

package demo
// 定义泛型函数 composition,复合两个函数
func composition<T1, T2, T3>(f: (T1) -> T2, g: (T2) -> T3): (T1) -> T3 {
return {x: T1 => g(f(x))}
}
// 定义两个函数
func times2(a: Int64): Int64 {
    return a * 3
}
func plus10(a: Int64): Int64 {
    return a + 10
}
// 定义一个函数,复合 times2 和 plus10
func times2plus10(a: Int64):Int64 {
    return composition<Int64, Int64, Int64>(times2, plus10)(a)
}

main() {
    println(times2plus10(9))  // 输出 37
    return 0
}

例7-10 局部泛型函数示例

7.4.1:函数内定义局部泛型函数 id,验证 id ~> double == double ~> id。

package demo
func foo(a: Int64):Bool{
    // 定义一个局部泛型函数 id
    func id<T>(a: T):T { 
        return a
    }    
    // 定义一个函数 double,返回 a 的两倍
    func double(a: Int64):Int64 {
        return a + a
    }    
    return (id<Int64> ~> double)(a) == (double ~> id<Int64>)(a)
}
main() {
    println(foo(1))  // 输出 true
    return 0
}

例7-11 泛型成员函数示例

7.4.1:class A、struct B、enum C 各定义泛型成员函数,要求 T <: ToString。

package demo
class A {
    // 定义一个泛型成员函数 foo,要求 T 必须符合 ToString 协议
    func foo<T>(a: T) where T <: ToString {
        println("${a}")
    }
}
struct B {
    // 定义一个泛型成员函数 bar,要求 T 必须符合 ToString 协议
    func bar<T>(a: T) where T<: ToString {
        println("${a}")
    }
}
enum C {
    X|Y    
    // 定义一个泛型成员函数 coo,要求 T 必须符合 ToString 协议
    func coo<T>(a: T): Unit where T <: ToString {
        println("${a}")
    }
}
main() {
    var a = A()
    var b = B()
    var c = C.X    
    // 调用泛型成员函数
    a.foo(10)          // 输出 10
    b.bar("abc")       // 输出 abc
    c.coo(true)        // 输出 true    
    return 0
}

例7-12 为 Int64 类型增加泛型成员函数

7.4.1:extend Int64 添加 printIntAndArg,同时输出 this 和泛型参数。

package demo
extend Int64 {
   func printIntAndArg<T>(a: T) where T <: ToString {
   println(this)
   println("${a}")
}
}
main() {
    var a: Int64 = 12
    a.printIntAndArg<String>("twelve") }

例7-13 静态泛型函数示例

7.4.1:ToPair 类的 static func fromArray 从 ArrayList 取前两个元素组成元组。

package demo
import std.collection.*
class ToPair {
    // 定义一个静态泛型函数 fromArray,返回一个元组
    public static func fromArray<T>(l: ArrayList<T>):(T, T) {
        return (l[0], l[1])
    }
}
main() {
    var res: ArrayList<Int64> = ArrayList([1, 2, 3, 4])
    var pair: (Int64, Int64) = ToPair.fromArray<Int64>(res)  // 调用静态泛型函数  
    println("(${pair[0]}, ${pair[1]})")  // 输出 (1, 2)
    return 0
}

例7-14 泛型接口示例

7.4.2:Iterable、Iterator、Collection 接口定义及 List/ListIterator 实现。

package demo
// 定义 Iterable 接口
public interface Iterable<E> {
    func iterator(): Iterator<E>  // 需要实现的函数
}

// 定义 Iterator 接口
public interface Iterator<E> <: Iterable<E> {
    func next(): Option<E>  // 需要实现的函数
}

// 实现 List 类型,它是一个容器类,并实现 Iterable 接口
class List<T> <: Iterable<T> {
    var elements: Array<T>  // 内部存储元素

    init(elements: Array<T>) {
        this.elements = elements
    }

    // 实现 Iterable 接口的 iterator 方法
    public func iterator(): Iterator<T> {
        return ListIterator<T>(this)  // 返回 ListIterator 实例
    }
}

// 实现 ListIterator 类型,它是一个 Iterator
class ListIterator<T> <: Iterator<T> {
    var list: List<T>
    var currentIndex: Int64 = 0

    init(list: List<T>) {
        this.list = list
    }

    // 实现 Iterator 接口的 next 方法
    public func next(): Option<T> {
        if (this.currentIndex < this.list.elements.size) {
            let value = this.list.elements[this.currentIndex]
            this.currentIndex += 1
            return Option.Some(value)  // 返回当前值
        } else {
            return Option.None  // 如果没有更多元素,返回 None
        }
    }
}

main() {
    // 创建一个 List 实例
    var myList = List<Int64>([1, 2, 3, 4, 5])

    // 获取 List 的 Iterator
    var iterator = myList.iterator()

    // 使用 iterator 遍历 List 中的元素
    while (true) {
        match (iterator.next()) {
            case Option.Some(value) => 
                println("Next value: ${value}")
            case Option.None => 
                println("End of list")
                break
        }
    }
}

例7-15 泛型类示例(Node

7.4.3:Node 用 Option 存储键值,要求 K <: Hashable & Equatable

package demo
// 定义泛型类 Node,K 是键类型,V 是值类型
public open class Node<K, V> where K <: Hashable & Equatable<K> {
    // 定义键和值,使用 Option 来存储它们
    public var key: Option<K> = Option<K>.None
    public var value: Option<V> = Option<V>.None
    // 默认构造函数
    public init() {}
    // 带键和值的构造函数
    public init(key: K, value: V) {
        this.key = Option<K>.Some(key)
        this.value = Option<V>.Some(value)
    }
}
main() {
    // 创建一个 Node 类型实例,键为 Int64 类型,值为 String 类型
    let node1 = Node<Int64, String>(123, "Hello")
    // 输出节点的键和值
    match (node1.key) {
        case Option.Some(k) => println("Key: ${k}")
        case Option.None => println("Key: None")
    }
    match (node1.value) {
        case Option.Some(v) => println("Value: ${v}")
        case Option.None => println("Value: None")
    }
    // 创建另一个 Node 类型实例,键为 String 类型,值为 Int64 类型
    let node2 = Node<String, Int64>("age", 30)
    // 输出节点的键和值
    match (node2.key) {
        case Option.Some(k) => println("Key: ${k}")
        case Option.None => println("Key: None")
    }
    match (node2.value) {
        case Option.Some(v) => println("Value: ${v}")
        case Option.None => println("Value: None")
    }
}

例7-16 泛型结构体示例(Pair)

7.4.4:struct Pair 存储两个不同类型元素,提供 first()/second() 访问。

package demo
// 定义一个结构体 Pair,接受两个类型形参 T 和 U
struct Pair<T, U> {
    let x: T  // 第一个元素
    let y: U  // 第二个元素
    // 构造函数,用于初始化 Pair 的值
    public init(a: T, b: U) {
        x = a
        y = b
    }
    // 第一个元素
    public func first(): T {
        return x
    }
    // 第二个元素
    public func second(): U {
        return y
    }
}
main() {
    // 创建一个 Pair 实例,类型为 Pair<String, Int64>
    var a: Pair<String, Int64> = Pair<String, Int64>("hello", 0)
    // 输出 Pair 中的第一个和第二个元素
    println(a.first())   // 输出 "hello"
    println(a.second())  // 输出 0
}

例7-17 泛型枚举示例(Option 与安全除法)

7.4.5:自定义 Option 枚举,safeDiv 除法在除数为零时返回 None。

package demo
public enum Option<T> {
    | Some(T) // Some 包装了类型 T 的值
    | None // 表示没有值

    // 获取 Option 中的值,如果是 Some,则返回其内部的值,否则抛出异常
    public func getOrThrow(): T {
        match (this) {
            case Some(v) => v
            case None => throw NoneValueException() // 如果是 None,则抛出异常
        }
    }
}
// 安全的除法函数
func safeDiv(a: Int64, b: Int64): Option<Int64> {
    var res: Option<Int64> = match (b) {
        case 0 => None // 除数为 0 时返回 None
        case _ => Some(a / b) // 否则返回 Some(a / b)
    }
    return res
}
main() {
    // 测试安全除法
    let result1 = safeDiv(10, 2)
    match (result1) {
        case Some(value) => println("The result is: ${value}") // 输出除法结果
        case None => println("Division by zero!") // 输出错误信息
    }

    let result2 = safeDiv(10, 0)
    match (result2) {
        case Some(value) => println("The result is: ${value}") // 不会执行
        case None => println("Division by zero!") // 输出错误信息
    }
}

例7-18 泛型别名示例

7.4.7:type RD = RecordData,使用别名简化泛型类型引用。

package demo
struct RecordData<T> {
var a: T
public init(x: T){
a = x
}
}

type RD<T> = RecordData<T>
main(): Int64 {
var struct1: RD<Int32> = RecordData<Int32>(2)
return 0
}  

例7-19 使用接口的泛型约束示例

7.4.8:genericPrint 要求 T <: ToString,100 可打印但 lambda 不行。

package demo
import std.core.*
//定义一个名为 genericPrint 的函数泛型类型 T 实现 ToString 接口
func genericPrint<T>(a: T) where T <:ToString {
    println(a)
    }
main() {
    genericPrint<Int64>(100)  // 100 会被转为字符串并打印
    return 0
}
// 以下是错误示例:
// package demo
// import std.core.*
// //定义一个名为 genericPrint 的函数泛型类型 T 实现 ToString 接口
// func genericPrint<T>(a: T) where T <:ToString {
//     println(a)
//     }
// main():Int64 {
//      genericPrint<(Int64) -> Int64>({ i => 0 })
//     return 0
// }

例7-20 使用接口约束的示例(Zoo)

7.4.8:Zoo where T <: Animal,确保只有 Animal 子类可加入动物园。

package demo
import std.collection.*
abstract class Animal {
    public func run(): String
}
class Dog <: Animal {
    public func run(): String {
        return "dog run"
    }
}
class Fox <: Animal {
    public func run(): String {
        return "fox run"
    }
}
class Zoo<T> where T <: Animal {
    var animals: ArrayList<Animal> = ArrayList<Animal>()
    
    public func addAnimal(a: T) {
        animals.add(a)
    }    
    public func allAnimalRuns() {
        for (a in animals) {
            println(a.run())  // 这里的 `run` 方法要求 `T` 必须是 `Animal` 的子类
        }
    }
}
main() {
    var zoo: Zoo<Animal> = Zoo<Animal>()
    zoo.addAnimal(Dog())  // 添加 Dog 到动物园
    zoo.addAnimal(Fox())  // 添加 Fox 到动物园
    zoo.allAnimalRuns()   // 输出所有动物的跑步动作
  }

五、扩展(7.5)

例7-21 为 Int64 类型添加 square 函数

7.5.2:extend Int64 添加 square() 返回平方值,直接用 num.square() 调用。

package demo
// 定义一个扩展来为 Int64 类型添加一个新函数
extend Int64 {
    // 添加一个新函数:返回该数字的平方
    func square(): Int64 {
        return this * this
    }
}
// 使用扩展的功能
main() {
    var num: Int64 = 5
    println(num.square()) // 输出:25
    return 0
}

例7-22 为 String 类型添加 printSize 函数

7.5.2:extend String 添加 printSize() 输出字符串长度。

package demo
// 定义一个扩展来为String 类型添加一个新函数printSize
extend String {
    public func printSize() {
    println("the size is ${this.size}")
}
}
// 使用扩展的功能
main() {
    let a = "123"
    a.printSize() // the size is 3
}

例7-23 泛型类型的扩展(Pair + Eq)

7.5.2:extend Pair 添加 equals,要求 T1/T2 均实现 Eq 接口。

package demo
class Pair<T1, T2> {
    var first: T1
    var second: T2
    public init(a: T1, b: T2) {
        first = a
        second = b
    }
}
interface Eq<T> {
    func equals(other: T): Bool
}
// 扩展 Pair<T1, T2> 类型,增加 equals 功能,前提是 T1 和 T2 都实现 Eq 接口
extend<T1, T2> Pair<T1, T2> where T1 <: Eq<T1>, T2 <: Eq<T2> {
    public func equals(other: Pair<T1, T2>) {
        first.equals(other.first) && second.equals(other.second)
    }
}
// 实现 Eq 接口的类 Foo
class Foo <: Eq<Foo> {
    public func equals(other: Foo): Bool {
        return true
    }
}
// 使用扩展的 Pair 类型
main() {
    let a = Pair(Foo(), Foo())
    let b = Pair(Foo(), Foo())
    println(a.equals(b)) // 输出:true
}

例7-24 扩展 Array 实现 PrintSizeable 接口

7.5.3:extend Array <: PrintSizeable,为数组类型添加接口实现。

package demo

interface PrintSizeable {
    func printSize(): Unit
}
extend<T> Array<T> <: PrintSizeable {
    public func printSize() {
        println("The size is ${this.size}")
    }
}
main() {
    let a: PrintSizeable = Array<Int64>()
    a.printSize() // 输出: The size is 0
}

六、程序举例(7.6)

示例1 用函数重载实现编译时的多态

area 函数三个重载版本:圆(Float64 半径)、矩形(长×宽)、正方形(边长)。

package demo

// 计算不同图形的面积:函数重载
func area(radius: Float64): Float64 {
    return 3.14 * radius * radius
}

func area(length: Int64, width: Int64): Int64 {
    return length * width
}

func area(side: Int64): Int64 {
    return side * side
}

main() {
    println("圆面积: ${area(3.0)}")
    println("矩形面积: ${area(4, 5)}")
    println("正方形面积: ${area(6)}")
}

示例2 用方法重写实现运行时多态

Shape → Circle/Rectangle,override func draw() 实现不同图形的绘制。

package demo

open class Shape {
    public open func draw() {
        println("绘制图形")
    }
}

class Circle <: Shape {
    public override func draw() {
        println("绘制圆形")
    }
}

class Rectangle <: Shape {
    public override func draw() {
        println("绘制矩形")
    }
}

main() {
    let s1: Shape = Circle()
    let s2: Shape = Rectangle()
    s1.draw()
    s2.draw()
}

示例3 类型判定与安全转换

Person/Student 类层次,is 判断 + as 转换,match 处理成功与失败分支。

package demo

open class Person {
    var name: String = "未知"
}

class Student <: Person {
    var grade: Int64 = 1
}

main() {
    let p1: Person = Student()
    // 使用 is 判断
    if (p1 is Student) {
        println("p1是学生类型")
    }
    // 使用 as 转换
    let result = p1 as Student
    match(result) {
        case Option.Some(s: Student) => println("转换成功,年级=${s.grade}")
        case Option.None => println("转换失败")
    }
}

示例4 泛型容器与交换函数

Box 泛型容器 + swap 泛型交换函数,展示泛型的基本用法。

package demo

// 定义泛型容器
class Box<T> {
    var value: T
    public init(v: T) { value = v }
    public func get(): T { return value }
}

// 泛型函数
func swap<T>(a: T, b: T): (T, T) {
    return (b, a)
}

main() {
    let intBox = Box<Int64>(100)
    let strBox = Box<String>("Hello")

    println("intBox: ${intBox.get()}")
    println("strBox: ${strBox.get()}")

    let res = swap<String>("A", "B")
    println("交换结果: (${res[0]}, ${res[1]})")
}

示例5 用 extend 扩展字符串

extend String 添加 wordCount() 方法,按空格分词统计单词数量。

package demo

// 为 String 扩展一个新方法:按空格分词统计单词数
extend String {
    public func wordCount(): Int64 {
        var count: Int64 = 0
        var inWord: Bool = false

        // 逐字节扫描;注意使用字节字面量 b' ' 作为空格
        for (b in this) {
            if (b == b' ') {
                if (inWord) {
                    inWord = false
                }
            } else {
                if (!inWord) {
                    count = count + 1   // 避免复合自增带来的类型推断问题
                    inWord = true
                }
            }
        }
        return count
    }
}

main(): Int64 {
    let s = "Hello   Cangjie Language"
    println("原字符串: '${s}'")
    println("单词数量: ${s.wordCount()}")
    return 0
}