仓颉语言扩展 Skill
- 扩展概述
1.1 目的
扩展为当前包中任何可见类型添加新功能 — 函数、元组和接口除外。
1.2 可添加的内容
-
成员函数
-
运算符重载函数
-
成员属性(带 get /set )
-
接口实现
1.3 不能做的事
-
添加成员变量(存储属性)
-
定义无实现体的函数/属性
-
对扩展成员使用 open 、override 或 redef
-
访问被扩展类型的 private 成员
1.4 两个类别
-
直接扩展:不涉及接口 — 仅添加函数/属性
-
接口扩展:为类型实现一个或多个接口
- 直接扩展
2.1 基本语法与示例
extend String { public func printSize() { println("the size is ${this.size}") } }
main() { let a = "123" a.printSize() // 输出:the size is 3 }
2.2 为类型添加属性和运算符
class Boo { var boo: Int64 = 2 }
extend Boo { public prop x: Int64 { // 添加成员属性 get() { 123 } }
public operator func -(): Int64 { // 添加运算符重载
-x
}
}
2.3 扩展泛型类型 — 两种形式
形式 A:扩展完全实例化的泛型类型:
class Foo<T> where T <: ToString {}
extend Foo<Int64> { ... } // 仅适用于 Foo<Int64>
形式 B:带新类型参数的泛型扩展:
class MyList<T> {}
extend<T> MyList<T> { ... } extend<T, R> MyList<(T, R)> { ... }
- extend 后声明的每个类型参数须在被扩展类型中使用
// ❌ 错误示例 extend MyList {} // Error: 泛型类型须带类型实参 extend<T, R> MyList<T> {} // Error: R 未被使用
2.4 扩展中的额外泛型约束
- 可添加 where 子句限制扩展成员的可用条件:
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 }
// 仅当 T1、T2 支持判等时,Pair 才有 equals 方法 extend<T1, T2> Pair<T1, T2> where T1 <: Eq<T1>, T2 <: Eq<T2> { public func equals(other: Pair<T1, T2>): Bool { first.equals(other.first) && second.equals(other.second) } }
- 接口扩展
3.1 基本语法
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 }
3.2 实现多个接口
使用 & 在一个扩展中实现多个接口:
interface I1 { func f1(): Unit } interface I2 { func f2(): Unit } interface I3 { func f3(): Unit } class Foo {}
extend Foo <: I1 & I2 & I3 { public func f1(): Unit {} public func f2(): Unit {} public func f3(): Unit {} }
3.3 已满足的接口成员
若类型已有所需成员,扩展体可为空:
interface Sizeable { prop size: Int64 }
extend<T> Array<T> <: Sizeable {} // Array 已有 prop size
main() { let a: Sizeable = Array<Int64>() println(a.size) // 输出:0 }
不能重新实现已存在的成员
3.4 接口继承与检查顺序
-
父接口扩展先检查,然后子接口
-
子接口的默认实现覆盖父接口的
-
两个无关接口提供同一成员的冲突默认实现 → 编译错误
interface I1 { func foo(): Unit { println("I1 foo") } } interface I2 <: I1 { func foo(): Unit { println("I2 foo") } } class A {}
extend A <: I1 {} // 先检查 extend A <: I2 {} // 后检查,I2.foo 覆盖 I1.foo
main() { A().foo() // 输出:I2 foo }
3.5 接口扩展中的泛型约束
// 当 T1、T2 可判等时,让 Pair 实现 Eq 接口 extend<T1, T2> Pair<T1, T2> <: Eq<Pair<T1, T2>> where T1 <: Eq<T1>, T2 <: Eq<T2> { public func equals(other: Pair<T1, T2>): Bool { first.equals(other.first) && second.equals(other.second) } }
- 访问规则
4.1 扩展级修饰符
- 扩展本身不能有修饰符
public class A {} public extend A {} // ❌ Error: 扩展前不能有修饰符
4.2 成员级修饰符
允许:static 、public 、protected 、internal 、private 、mut
修饰符 作用域
private
仅在扩展块内
internal
当前包及子包(默认)
protected
当前模块
public
全局可见
static
仅通过类型名访问
mut
结构体扩展中的可变函数
不允许用于扩展成员的修饰符:open 、override 、redef
4.3 扩展 struct 的 mut 函数
struct Counter { var count: Int64 = 0 }
extend Counter { public mut func increment() { count += 1 } }
main() { var c = Counter() // 须为 var 才能调用 mut 函数 c.increment() println(c.count) // 输出:1 }
4.4 孤儿规则
不能为接口和类型均来自不同包的情况实现接口。扩展须与被扩展类型或接口(含接口继承链上的所有接口)在同一个包中。
// package a public class Foo {}
// package b public interface Bar {}
// package c import a.Foo import b.Bar extend Foo <: Bar {} // ❌ Error: 孤儿扩展 // 须在 package a 或 package b 中为 Foo 实现 Bar
4.5 this 和 super
-
扩展实例成员可以使用 this (可省略)
-
扩展实例成员不能使用 super
class A { var v = 0 } extend A { func f() { print(this.v) // OK print(v) // OK,省略 this } }
4.6 不能访问 private 成员
扩展不能读写被扩展类型的 private 成员。protected 及以上可访问
class A { private var v1 = 0 protected var v2 = 0 } extend A { func f() { print(v1) // ❌ Error: 不能访问 private 成员 print(v2) // OK } }
4.7 不能遮蔽
-
扩展不能重定义类型上已有的成员
-
扩展不能重定义同一类型的另一个扩展中的成员
class A { func f() {} } extend A { func f() {} // ❌ Error: 不能遮蔽已有成员 }
// 两个扩展之间也不能遮蔽 extend A { func g() {} } extend A { func g() {} // ❌ Error }
4.8 跨扩展可见性(同一包)
-
同一包中允许同一类型的多个扩展
-
一个扩展中的非 private 成员可从另一个扩展调用
-
private 成员仅限于其自己的扩展块
class Foo {}
extend Foo { private func f() {} func g() {} // 默认 internal }
extend Foo { func h() { g() // OK: 可访问其他扩展的非 private 成员 f() // ❌ Error: f 是 private } }
4.9 泛型扩展可见性规则
-
相同约束 → 互相可见
-
子集约束 → 较宽松扩展的成员对较严格扩展可见,反之不可
-
无关约束 → 互相不可见
open class A {} class B <: A {} class E<X> {}
interface I1 { func f1(): Unit } interface I2 { func f2(): Unit }
extend<X> E<X> <: I1 where X <: B { // 扩展 1(更严格) public func f1(): Unit { f2() // OK: 较宽松扩展的成员可见 } }
extend<X> E<X> <: I2 where X <: A { // 扩展 2(更宽松) public func f2(): Unit { f1() // ❌ Error: 较严格扩展的成员不可见 } }
4.10 导出规则
直接扩展
-
与被扩展类型同包时,当类型和所有泛型约束均为导出类型时导出
-
不同包时,永不导出
接口扩展(与类型同包)
- 随类型一起导出,无论接口的访问级别如何
接口扩展(与类型不同包)
-
导出由所实现接口和泛型约束中最低访问级别决定
-
仅接口中声明的成员被导出
4.11 导入规则
-
扩展隐式导入 — 无需显式 import 扩展本身
-
直接扩展:导入被扩展类型自动导入其导出的直接扩展
-
接口扩展:须同时导入被扩展类型和接口才能访问扩展成员
// package a package a public class Foo {} extend Foo { public func f() {} }
// package b package b import a.Foo public interface I { func g(): Unit } extend Foo <: I { public func g() { this.f() } // OK }
// package c — 使用扩展 package c import a.Foo import b.I
func test() { let a = Foo() a.f() // OK:直接扩展随 Foo 导入 a.g() // OK:已导入 Foo 和 I }