引言
仓颉语言的扩展系统是一个强大而灵活的特性,它允许我们为现有类型添加新功能,而无需修改原始类型定义。这种设计既保持了类型的封装性,又提供了极大的扩展灵活性。
1. 扩展系统概述
1.1 什么是扩展
扩展是仓颉语言中为现有类型添加新功能的一种机制。它可以在不破坏被扩展类型封装性的前提下,为类型添加:
- 成员函数
- 操作符重载函数
- 成员属性
- 接口实现
总之一句话:只能扩展行为,不能扩展存储
1.2 扩展的基本语法
cangjie
// 基本扩展语法
extend 类型名 {
// 扩展的成员
}
// 带泛型的扩展语法
extend<泛型参数> 泛型类型<泛型参数> {
// 扩展的成员
}
// 接口扩展语法
extend 类型名 <: 接口名 {
// 实现接口的成员
}
1.3 扩展的限制
扩展虽然强大,但也有明确的限制:
- 不能增加成员变量:只能添加函数和属性,不能添加字段
- 必须提供实现:扩展的函数和属性必须有具体实现
- 不能使用特定修饰符 :不支持
open
、override
、redef
- 访问权限受限 :不能访问被扩展类型的
private
成员
2. 直接扩展详解
2.1 基本直接扩展
直接扩展是最简单的扩展形式,不包含接口实现:
cangjie
// 为 String 类型添加 printSize 函数
extend String {
public func printSize():Unit {
println("字符串的长度是: ${this.size}")
}
// 添加计算属性
public prop isLong: Bool {
get() {
this.size > 10
}
}
}
// 使用扩展
main() {
let text = "这是一个很长的字符串示例"
text.printSize() // 输出: 字符串的长度是: 36 String底层存储的字节,所以一个中文可能对应多个字节
println(text.isLong) // 输出: true
}
2.2 泛型类型的直接扩展
2.2.1 特定泛型实例化扩展
cangjie
import std.unicode.UnicodeStringExtension
// 定义泛型容器类
class Container<T> {
var data: T
public init(value: T) {
data = value
}
}
// 为特定类型实例化进行扩展
extend Container<Int64> {
public func doubleValue():Unit {
data = data * 2
}
public func isEven(): Bool {
data % 2 == 0
}
}
// 为另一个特定类型实例化进行扩展
extend Container<String> {
public func toUpperCase():Unit {
data = data.toUpper()
}
public func length(): Int64 {
data.size
}
}
main() {
let intContainer = Container(123)
intContainer.doubleValue()
println(intContainer.data) // 输出: 246
println(intContainer.isEven()) // 输出: true
let stringContainer = Container("hello")
stringContainer.toUpperCase()
println(stringContainer.data) // 输出: HELLO
println(stringContainer.length()) // 输出: 5
}
2.2.2 泛型扩展
cangjie
import std.collection.ArrayList
// 定义泛型列表类
class MyList<T> {
var items: ArrayList<T> = ArrayList<T>()
public func add(item: T): Unit {
items.add(item)
}
public func get(index: Int64): ?T {
if (index >= 0 && index < items.size) {
items[index]
} else {
None
}
}
}
// 泛型扩展 - 为所有类型添加基础功能
extend<T> MyList<T> {
public func isEmpty(): Bool {
items.size == 0
}
public func size(): Int64 {
items.size
}
public func clear(): Unit {
items = ArrayList<T>()
}
}
// 带约束的泛型扩展 - 为可比较类型添加排序功能
extend<T> MyList<T> where T <: Comparable<T> {
public func sort(): Unit {
// 简单的冒泡排序实现
for (i in 0..items.size) {
for (j in 0..(items.size - i - 1)) {
if (items[j] > items[j + 1]) {
(items[j], items[j + 1]) = (items[j + 1], items[j])
}
}
}
}
public func contains(item: T): Bool {
for (element in items) {
if (element == item) {
return true
}
}
false
}
}
// 使用扩展
main() {
let intList = MyList<Int64>()
intList.add(3)
intList.add(1)
intList.add(4)
intList.add(2)
println("列表大小: ${intList.size()}") // 输出: 列表大小: 4
println("是否为空: ${intList.isEmpty()}") // 输出: 是否为空: false
intList.sort()
println("排序后包含2: ${intList.contains(2)}") // 输出: 排序后包含2: true
let stringList = MyList<String>()
stringList.add("banana")
stringList.add("apple")
stringList.add("cherry")
stringList.sort()
println("排序后的第一个元素: ${stringList.get(0)}") // 输出: 排序后的第一个元素: apple
}
2.3 高级泛型扩展示例
cangjie
// 定义可比较接口
interface Comparable<T> {
func equals(other: T): Bool
func lessThan(other: T): Bool
}
// 定义可序列化接口
interface Serializable {
func serialize(): String
}
// 定义泛型对类
class Pair<T1, T2> {
let first: T1
let second: T2
public init(a: T1, b: T2) {
first = a
second = b
}
}
// 为可比较类型对添加比较功能
extend<T1, T2> Pair<T1, T2> where T1 <: Comparable<T1>, T2 <: Comparable<T2> {
public func equals(other: Pair<T1, T2>): Bool {
first.equals(other.first) && second.equals(other.second)
}
public func lessThan(other: Pair<T1, T2>): Bool {
if (first.equals(other.first)) {
second.lessThan(other.second)
} else {
first.lessThan(other.first)
}
}
}
// 为可序列化类型对添加序列化功能
extend<T1, T2> Pair<T1, T2> where T1 <: Serializable, T2 <: Serializable {
public func serialize(): String {
"(${first.serialize()}, ${second.serialize()})"
}
}
// 实现具体类型
class IntWrapper <: Comparable<IntWrapper> & Serializable {
let value: Int64
public init(v: Int64) {
value = v
}
public func equals(other: IntWrapper): Bool {
value == other.value
}
public func lessThan(other: IntWrapper): Bool {
value < other.value
}
public func serialize(): String {
"Int(${value})"
}
}
main() {
let pair1 = Pair(IntWrapper(1), IntWrapper(2))
let pair2 = Pair(IntWrapper(1), IntWrapper(3))
println("pair1 等于 pair2: ${pair1.equals(pair2)}") // 输出: false
println("pair1 小于 pair2: ${pair1.lessThan(pair2)}") // 输出: true
println("pair1 序列化: ${pair1.serialize()}") // 输出: (Int(1), Int(2))
}
3. 接口扩展详解
3.1 基本接口扩展
接口扩展允许我们为现有类型实现接口,这是扩展系统最强大的功能之一:
cangjie
import std.collection.{collectString}
// 定义可打印接口
interface Printable {
func print(): Unit
}
// 定义可序列化接口
interface Serializable {
func serialize(): String
}
// 为 Array 实现 Printable 接口
extend<T> Array<T> <: Printable where T <: ToString {
public func print(): Unit {
println("数组内容: [${collectString(delimiter: ", ")(this)}]")
}
}
// 为 Array 实现 Serializable 接口
extend<T> Array<T> <: Serializable {
public func serialize(): String {
"Array[${this.size}]"
}
}
// 使用接口扩展
main() {
let numbers: Array<Int64> = [1, 2, 3, 4, 5]
// 通过接口类型使用
let printable: Printable = numbers
printable.print() // 输出: 数组内容: [1, 2, 3, 4, 5]
let serializable: Serializable = numbers
println(serializable.serialize()) // 输出: Array[5]
// 直接使用扩展的方法
numbers.print()
println(numbers.serialize())
}
3.2 多接口实现
cangjie
// 定义多个接口
interface Drawable {
func draw(): Unit
}
interface Movable {
func move(x: Int64, y: Int64): Unit
}
interface Resizable {
func resize(width: Int64, height: Int64): Unit
}
// 定义矩形类
class Rectangle {
var x: Int64 = 0
var y: Int64 = 0
var width: Int64 = 100
var height: Int64 = 50
}
// 通过扩展实现多个接口
extend Rectangle <: Drawable & Movable & Resizable {
public func draw(): Unit {
println("绘制矩形: 位置(${x}, ${y}), 尺寸(${width} x ${height})")
}
public func move(newX: Int64, newY: Int64): Unit {
x = newX
y = newY
println("矩形移动到: (${x}, ${y})")
}
public func resize(newWidth: Int64, newHeight: Int64): Unit {
width = newWidth
height = newHeight
println("矩形尺寸调整为: ${width} x ${height}")
}
}
main() {
let rect = Rectangle()
// 通过接口类型使用
let drawable: Drawable = rect
let movable: Movable = rect
let resizable: Resizable = rect
drawable.draw()
movable.move(10, 20)
resizable.resize(200, 100)
// 直接使用
rect.draw()
rect.move(30, 40)
rect.resize(150, 75)
}
3.3 带约束的接口扩展
cangjie
// 定义数值接口
interface Numeric<T> {
func add(other: T): T
func subtract(other: T): T
func multiply(other: T): T
func divide(other: T): T
}
// 定义统计接口
interface Statistic<T> {
func sum(): T
func average(): T
func max(): T
func min(): T
}
// 为数值数组实现统计接口
extend<T> Array<T> <: Statistic<T> where T <: Numeric<T> {
public func sum(): T {
if (isEmpty()) {
// 需要返回零值,这里简化处理
this[0]
} else {
var result = this[0]
for (i in 1..size) {
result = result.add(this[i])
}
result
}
}
public func average(): T {
// 简化实现,实际需要类型转换
this.sum()
}
public func max(): T {
var maxVal = this[0]
for (item in this) {
// 这里需要比较操作,简化处理
maxVal = item
}
maxVal
}
public func min(): T {
var minVal = this[0]
for (item in this) {
// 这里需要比较操作,简化处理
minVal = item
}
minVal
}
}
// 实现具体的数值类型
class ComplexNumber <: Numeric<ComplexNumber> {
var real: Float64
var imaginary: Float64
public init(r: Float64, i: Float64) {
real = r
imaginary = i
}
public func add(other: ComplexNumber): ComplexNumber {
ComplexNumber(real + other.real, imaginary + other.imaginary)
}
public func subtract(other: ComplexNumber): ComplexNumber {
ComplexNumber(real - other.real, imaginary - other.imaginary)
}
public func multiply(other: ComplexNumber): ComplexNumber {
let newReal = real * other.real - imaginary * other.imaginary
let newImaginary = real * other.imaginary + imaginary * other.real
ComplexNumber(newReal, newImaginary)
}
public func divide(other: ComplexNumber): ComplexNumber {
// 简化实现
ComplexNumber(real / other.real, imaginary / other.imaginary)
}
public func toString(): String {
"${real} + ${imaginary}i"
}
}
main() {
let numbers = [
ComplexNumber(1.0, 2.0),
ComplexNumber(3.0, 4.0),
ComplexNumber(5.0, 6.0)
]
println("复数数组统计:")
println("第一个数: ${numbers[0].toString()}")
println("第二个数: ${numbers[1].toString()}")
println("第三个数: ${numbers[2].toString()}")
}
3.4 接口继承与扩展顺序
cangjie
// 定义基础接口
interface Animal {
func makeSound(): Unit {
println("动物发出声音")
}
func move(): Unit {
println("动物移动")
}
}
// 定义哺乳动物接口
interface Mammal <: Animal {
func makeSound(): Unit {
println("哺乳动物发出声音")
}
func giveBirth(): Unit {
println("哺乳动物生育")
}
}
// 定义鸟类接口
interface Bird <: Animal {
func makeSound(): Unit {
println("鸟类发出声音")
}
func fly(): Unit {
println("鸟类飞行")
}
}
// 定义鸭嘴兽类(既是哺乳动物又是鸟类)
// 如果多个接口中有重载方法,需要在类声明中就遵守并实现他们共同的父接口或者选择一个接口实现
// 其余的接口可以在声明中实现或在扩展中实现
class Platypus <: Animal {
// 这里如果不重新实现move方法,Platypus依然会有move方法,只不过它的实现是Animal中move的默认实现
public func move(): Unit {
println("鸭嘴兽游泳")
}
public func makeSound(): Unit {
println("鸭嘴兽发出声音")
}
}
// 实现哺乳动物接口
extend Platypus <: Mammal {
public func giveBirth(): Unit {
println("鸭嘴兽产卵")
}
}
// 实现鸟类接口
extend Platypus <: Bird {
public func fly(): Unit {
println("鸭嘴兽不能飞行")
}
}
main() {
let platypus = Platypus()
// 通过不同接口类型调用
let animal: Animal = platypus
let mammal: Mammal = platypus
let bird: Bird = platypus
println("=== 通过 Animal 接口调用 ===")
animal.makeSound() // 输出: 哺乳动物发出声音
animal.move() // 输出: 鸭嘴兽游泳
println("=== 通过 Mammal 接口调用 ===")
mammal.makeSound() // 输出: 哺乳动物发出声音
mammal.move() // 输出: 鸭嘴兽游泳
mammal.giveBirth() // 输出: 鸭嘴兽产卵
println("=== 通过 Bird 接口调用 ===")
bird.makeSound() // 输出: 鸟类发出声音
bird.move() // 输出: 鸭嘴兽游泳
bird.fly() // 输出: 鸭嘴兽不能飞行
}
4. 访问规则详解
4.1 扩展修饰符规则
cangjie
// 扩展本身不能使用修饰符
class Example {}
// 错误:扩展不能使用修饰符
// public extend Example {} // 编译错误
// 正确:扩展成员可以使用修饰符
extend Example {
// 公共成员 - 任何地方都可以访问
public func publicMethod(): Unit {
println("公共方法")
}
// 受保护成员 - 本模块内可访问,子类可访问
protected func protectedMethod() {
println("受保护方法")
}
// 内部成员 - 当前包及子包内可访问(默认)
internal func internalMethod() {
println("内部方法")
}
// 私有成员 - 只能在本扩展内使用
private func privateMethod() {
println("私有方法")
}
// 静态成员 - 只能通过类型名访问
static func staticMethod() {
println("静态方法")
}
// 可变函数 - 可以修改被扩展类型的成员
func mutableMethod() {
// 这里可以修改被扩展类型的可变成员
println("可变方法")
}
}
main() {
let example = Example()
// 调用公共方法
example.publicMethod()
// 调用受保护方法
example.protectedMethod()
// 调用内部方法
example.internalMethod()
// 调用静态方法
Example.staticMethod()
// 调用可变方法
example.mutableMethod()
// 以下调用会编译错误
// example.privateMethod() // 错误:私有方法
}
4.2 扩展的孤儿规则
cangjie
// 包 a 中的类型
package cangjie_blog.a
public class MyClass {
var value: Int64 = 0
public init(v: Int64) {
value = v
}
}
// 包 b 中的接口
package cangjie_blog.b
public interface MyInterface {
func interfaceMethod(): Unit
}
// 包 c 中的扩展(错误示例)
package cangjie_blog.c
import cangjie_blog.a.MyClass
import cangjie_blog.b.MyInterface
// 错误:孤儿扩展 - 既不在接口包中,也不在被扩展类型包中
// imported type 'MyClass' cannot extend imported interface, used external interface: Interface-MyInterface
// extend MyClass <: MyInterface {
// public func interfaceMethod() {
// println("实现接口方法")
// }
// }
// 正确的做法:在包 a 中扩展
// 在 a 包中添加:
// extend MyClass <: MyInterface {
// public func interfaceMethod():Unit {
// println("实现接口方法")
// }
// }
// 或者在包 b 中扩展
// 在 b 包中添加:
// extend MyClass <: MyInterface {
// public func interfaceMethod(): Unit {
// println("实现接口方法")
// }
// }
4.3 扩展的访问和遮盖规则
cangjie
class BaseClass {
var publicField: Int64 = 10
protected var protectedField: Int64 = 20
private var privateField: Int64 = 30
func baseMethod() {
println("基础方法")
}
func overridableMethod() {
println("可重写方法")
}
}
// 第一个扩展
extend BaseClass {
func extensionMethod1() {
// 可以访问公共和受保护成员
println("公共字段值: ${publicField}")
println("受保护字段值: ${protectedField}")
// 不能访问私有成员
// println("私有字段值: ${privateField}") // 编译错误
// 可以调用基础方法
baseMethod()
}
// 不能遮盖现有方法
// func baseMethod() { // 编译错误:不能遮盖现有方法
// println("扩展方法")
// }
// 不能使用 override 修饰符
// override func overridableMethod() { // 编译错误
// println("重写的方法")
// }
}
// 第二个扩展
extend BaseClass {
func extensionMethod2() {
// 可以调用第一个扩展的方法
extensionMethod1()
// 可以访问基础类的成员
println("访问基础字段: ${publicField}")
}
// 不能遮盖第一个扩展的方法
// func extensionMethod1() { // 编译错误:不能遮盖其他扩展的方法
// println("遮盖的方法")
// }
}
main() {
let obj = BaseClass()
// 调用扩展方法
obj.extensionMethod1()
obj.extensionMethod2()
// 调用基础方法
obj.baseMethod()
}
4.4 泛型扩展的可见性规则
cangjie
// 定义基础接口
interface BaseInterface {
func baseMethod(): Unit
}
// 定义派生接口
interface DerivedInterface <: BaseInterface {
func derivedMethod(): Unit
}
// 定义泛型类
class GenericClass<T> {
var data: T
public init(value: T) {
data = value
}
}
// 扩展0:约束非常宽松
extend<T> GenericClass<T> {
// 对于BaseInterface和DerivedInterface中的baseMethod。
// 如果GenericClass分别扩展了它们,这个共同的方法必须在最宽松的扩展里面实现,否则报错
public func baseMethod(): Unit {
println("扩展0实现基础方法")
}
}
// 扩展1:约束更严格
// 扩展0更宽松
extend<T> GenericClass<T> <: BaseInterface where T <: DerivedInterface {
// public func baseMethod(): Unit {
// println("扩展1实现基础方法")
// data.derivedMethod() // 可以调用派生接口方法
// }
public func extension1Method():Unit {
println("扩展1的专用方法")
}
}
// 扩展2:约束更宽松
// 约束更宽松的对约束更严格的可见,反之不可见。所以extension2Method中无法调用extension1Method
//
extend<T> GenericClass<T> <: DerivedInterface where T <: BaseInterface {
// public func baseMethod(): Unit {
// println("扩展2实现基础方法")
// }
public func derivedMethod(): Unit {
println("扩展2实现派生方法")
}
func extension2Method() {
// extension1Method()
}
}
// 实现具体接口
class ConcreteClass <: DerivedInterface {
public func baseMethod(): Unit {
println("具体类实现基础方法")
}
public func derivedMethod(): Unit {
println("具体类实现派生方法")
}
}
main() {
let concrete = ConcreteClass()
let generic = GenericClass(concrete)
// 通过基础接口调用
let base: BaseInterface = generic
base.baseMethod()
// 通过派生接口调用
let derived: DerivedInterface = generic
derived.baseMethod()
derived.derivedMethod()
// 直接调用扩展方法
generic.extension1Method()
generic.extension2Method()
}
5. 扩展的导入导出规则
5.1 直接扩展的导入导出
cangjie
// 包 cangjie_blog.a.b 中的定义
package cangjie_blog.a.b
// 对于直接扩展,当扩展与被扩展的类型在同一个包中
// 扩展是否导出,由被扩展类型与泛型约束(如果有)的访问修饰符同时决定
// 当所有的泛型约束都是导出类型(修饰符与导出规则,详见顶层声明的可见性章节)时,该扩展将被导出
// 私有接口 - 不导出
private interface PrivateInterface {
// 协议里的方法都是公开的
func privateMethod(): Unit
}
public class Cls4PrivateInterface <: PrivateInterface {
public func privateMethod(): Unit {
println("Cls4PrivateInterface 实现privateMethod")
}
}
// 内部接口 - 子包可见
internal interface InternalInterface {
func internalMethod(): Unit
}
public class Cls4InternalInterface <: InternalInterface {
public func internalMethod(): Unit {
println("Cls4InternalInterface 实现internalMethod")
}
}
// 受保护接口 - 模块内可见
protected interface ProtectedInterface {
func protectedMethod(): Unit
}
public class Cls4ProtectedInterface <: ProtectedInterface {
public func protectedMethod(): Unit {
println("Cls4ProtectedInterface 实现protectedMethod")
}
}
// 公共接口 -
public interface PublicInterface {
func publicMethod(): Unit
}
public class Cls4PublicInterface <: PublicInterface {
public func publicMethod(): Unit {
println("Cls4PublicInterface 实现publicMethod")
}
}
public class Cls4All <: PrivateInterface & InternalInterface & ProtectedInterface & PublicInterface {
public func privateMethod(): Unit {
println("Cls4All 实现privateMethod")
}
public func internalMethod(): Unit {
println("Cls4All 实现internalMethod")
}
public func protectedMethod(): Unit {
println("Cls4All 实现protectedMethod")
}
public func publicMethod(): Unit {
println("Cls4All 实现publicMethod")
}
}
// 公共类 - 完全导出
public class PublicClass<T> {
var data: T
public init(value: T) {
data = value
}
}
// 直接扩展1:不导出(泛型约束未导出)
extend<T> PublicClass<T> where T <: PrivateInterface {
public func method1(): Unit {
data.privateMethod()
println("方法1 - 不导出")
}
}
// 直接扩展2::不导出(泛型约束未导出)
extend<T> PublicClass<T> where T <: InternalInterface {
public func method2(): Unit {
data.internalMethod()
println("方法2 - 导出")
}
}
// 直接扩展3:导出(泛型约束导出)
extend<T> PublicClass<T> where T <: ProtectedInterface {
public func method3(): Unit {
data.protectedMethod()
println("方法3 - 导出")
}
}
// 直接扩展4:导出(泛型约束导出)
extend<T> PublicClass<T> where T <: PublicInterface {
public func method4(): Unit {
data.publicMethod()
println("方法4 - 导出")
}
}
// 包 cangjie_blog.a.c 中的使用
package cangjie_blog.a.c
import cangjie_blog.a.b.*
class A <: ProtectedInterface {
public func protectedMethod(): Unit {
println("A实现protectedMethod")
}
}
main() {
let obj = PublicClass(123)
// 123未实现PrivateInterface、 InternalInterface、ProtectedInterface,所以以下方法不可见,调用会编译错误
// 错误:约束不可见
// obj.method1()
// obj.method2()
// obj.method3()
// obj.method4()
let obj2 = PublicClass(A())
// A实现了ProtectedInterface接口,所以a包中直接扩展的methods对此可见
obj2.method3()
let objPrivate = PublicClass(Cls4PrivateInterface())
// PrivateInterface被private修饰 扩展未导出
// 以下方法报错
// objPrivate.method1()
// objPrivate.method2()
// objPrivate.method3()
// objPrivate.method4()
let objInternal = PublicClass(Cls4InternalInterface())
// InternalInterface被internal修饰 扩展未导出
// 以下方法报错
// objInternal.method1()
// objInternal.method2()
// objInternal.method3()
// objInternal.method4()
let objProtected = PublicClass(Cls4ProtectedInterface())
// 以下方法报错
// objProtected.method1()
// objProtected.method2()
// ProtectedInterface被protected修饰 扩展被导出了,但是data实现了ProtectedInterface接口,只有method3可见
objProtected.method3()
// objProtected.method4()
let objPublic = PublicClass(Cls4PublicInterface())
// 以下方法报错
// objPublic.method1()
// objPublic.method2()
// objPublic.method3()
// PublicInterface被public修饰 扩展被导出了,但是data实现了PublicInterface接口,只有method4可见
objPublic.method4()
let objAll = PublicClass(Cls4All())
// Cls4All实现了4个接口,扩展导出以最低修饰符为准。即以private为准。导致扩展未被导出
// objAll.privateMethod()
// objAll.internalMethod()
// objAll.protectedMethod()
// objAll.publicMethod()
}
package cangjie_blog.a.b.d
import cangjie_blog.a.b.*
class A <: ProtectedInterface {
public func protectedMethod(): Unit {
println("A实现protectedMethod")
}
}
main() {
let obj = PublicClass(123)
// 123未实现PrivateInterface、 InternalInterface、ProtectedInterface,所以以下方法不可见,调用会编译错误
// 错误:约束不可见
// obj.method1()
// obj.method2()
// obj.method3()
// obj.method4()
let obj2 = PublicClass(A())
// A实现了ProtectedInterface接口,所以a包中直接扩展的methods对此可见
obj2.method3()
let objPrivate = PublicClass(Cls4PrivateInterface())
// PrivateInterface被private修饰 扩展未导出
// 以下方法报错
// objPrivate.method1()
// objPrivate.method2()
// objPrivate.method3()
// objPrivate.method4()
let objInternal = PublicClass(Cls4InternalInterface())
// objInternal.method1()
// InternalInterface被internal修饰 此包作为package cangjie_blog.a.b的子包,扩展被导出了
// 但是data实现了InternalInterface接口,只有method2可见
objInternal.method2()
// objInternal.method3()
// objInternal.method4()
let objProtected = PublicClass(Cls4ProtectedInterface())
// 以下方法报错
// objProtected.method1()
// objProtected.method2()
// ProtectedInterface被protected修饰 扩展被导出了,但是data实现了ProtectedInterface接口,只有method3可见
objProtected.method3()
// objProtected.method4()
let objPublic = PublicClass(Cls4PublicInterface())
// 以下方法报错
// objPublic.method1()
// objPublic.method2()
// objPublic.method3()
// PublicInterface被public修饰 扩展被导出了,但是data实现了PublicInterface接口,只有method4可见
objPublic.method4()
}
5.2 接口扩展的导入导出
cangjie
// 包 a 中的定义
package cangjie_blog.exportdemo.a
// 私有接口
private interface PrivateInterface {
func privateMethod(): Unit
}
// 公共类
public class PublicClass<T> {
var data: T
public init(value: T) {
data = value
}
}
// 接口扩展:会被导出(与被扩展类型在同一包中)
extend<T> PublicClass<T> <: PrivateInterface {
public func privateMethod(): Unit {
println("实现私有接口方法")
}
}
// 包 b 中的扩展
package cangjie_blog.exportdemo.b
import cangjie_blog.exportdemo.a.PublicClass
// 私有接口
private interface LocalInterface {
func localMethod(): Unit
}
// 内部接口
internal interface InternalInterface {
func internalMethod(): Unit
}
// 受保护接口
protected interface ProtectedInterface {
func protectedMethod(): Unit
}
// 公共接口
public interface PublicInterface {
func publicMethod(): Unit
}
// 当接口扩展与被扩展类型在不同的 package 时,接口扩展是否导出由接口类型以及泛型约束(如果有)里用到的类型中最小的访问级别决定。
// 其他 package 必须导入被扩展类型、相应的接口以及约束用到的类型(如果有),才能访问对应接口包含的扩展成员
// 扩展1:不导出(接口不可见)
extend<T> PublicClass<T> <: LocalInterface {
public func localMethod(): Unit {
println("本地接口方法")
}
}
// 扩展2:导出(接口可见)
extend<T> PublicClass<T> <: InternalInterface {
public func internalMethod(): Unit {
println("内部接口方法")
}
}
// 扩展3:导出(接口可见)
extend<T> PublicClass<T> <: ProtectedInterface {
public func protectedMethod(): Unit {
println("受保护接口方法")
}
}
// 扩展4:导出(接口可见)
extend<T> PublicClass<T> <: PublicInterface {
public func publicMethod(): Unit {
println("公共接口方法")
}
}
// 扩展5:扩展实现错误
// 这里因为扩展4和扩展5都是实现PublicInterface,但扩展4中无泛型约束,更加宽松,publicMethod又没有泛型参数,所以这里无法再重新实现接口
// interface 'Interface-PublicInterface' has been implemented by 'Class-PublicClass<Generics-T>', please remove it
// extend<T> PublicClass<T> <: PublicInterface where T <: LocalInterface {
// // public func publicMethod(): Unit {
// // println("公共接口方法")
// // }
// public func constrainedMethod(): Unit {
// println("约束方法")
// }
// }
// 扩展6:扩展实现错误
// 原因同上
// interface 'Interface-PublicInterface' has been implemented by 'Class-PublicClass<Generics-T>', please remove it
// extend<T> PublicClass<T> <: PublicInterface where T <: ProtectedInterface {
// public func mixedMethod(): Unit {
// println("混合方法")
// }
// }
// 包 c 中的使用
package cangjie_blog.exportdemo.c
import cangjie_blog.exportdemo.a.PublicClass
// internal修饰的接口,无法跨包可见
// import cangjie_blog.exportdemo.b.InternalInterface
// protected修饰的接口,可以在整个模块内可见
import cangjie_blog.exportdemo.b.ProtectedInterface
import cangjie_blog.exportdemo.b.PublicInterface
main() {
let obj = PublicClass(123)
// 以下调用会编译错误
// obj.localMethod() // 错误:扩展未导出
// obj.constrainedMethod() // 错误:扩展未导出
// 以下调用成功
// obj.internalMethod() // 成功:扩展已导出
obj.protectedMethod() // 成功:扩展已导出
obj.publicMethod() // 成功:扩展已导出
// obj.mixedMethod() // 成功:扩展已导出
}
6. 实际应用场景
6.1 为第三方库添加功能
cangjie
package cangjie_blog
// 假设这是第三方库中的类
class ThirdPartyClass {
var id: Int64
var name: String
public init(id: Int64, name: String) {
this.id = id
this.name = name
}
}
// 通过扩展添加序列化功能
interface JSONSerializable {
func toJSON(): String
}
extend ThirdPartyClass <: JSONSerializable {
public func toJSON(): String {
"{\"id\": ${id}, \"name\": \"${name}\"}"
}
}
// 通过扩展添加验证功能
interface Validatable {
func validate(): Bool
}
extend ThirdPartyClass <: Validatable {
public func validate(): Bool {
id > 0 && name.size > 0
}
}
main() {
let obj = ThirdPartyClass(1, "测试对象")
// 使用扩展的功能
if (obj.validate()) {
println("对象有效")
println("JSON格式: ${obj.toJSON()}")
}
}
6.2 为内置类型添加功能
cangjie
package cangjie_blog
import std.math.sqrt
import std.collection.ArrayList
import std.unicode.{UnicodeRuneExtension, UnicodeStringExtension}
// 为 Int64 添加数学工具函数
extend Int64 {
// 判断是否为质数
public func isPrime(): Bool {
if (this < 2) {
return false
}
if (this == 2) {
return true
}
if (this % 2 == 0) {
return false
}
let sqrt = Int64(sqrt(Float64(this)))
for (i in 3..=sqrt : 2) {
if (this % i == 0) {
return false
}
}
true
}
// 计算阶乘
public func factorial(): Int64 {
if (this <= 1) {
1
} else {
this * (this - 1).factorial()
}
}
// 转换为罗马数字
public func toRoman(): String {
if (this == 0) {
return "N"
}
let romanNumerals = [
(1000, "M"),
(900, "CM"),
(500, "D"),
(400, "CD"),
(100, "C"),
(90, "XC"),
(50, "L"),
(40, "XL"),
(10, "X"),
(9, "IX"),
(5, "V"),
(4, "IV"),
(1, "I")
]
var result = ""
var remaining = this
for ((value, numeral) in romanNumerals) {
while (remaining >= value) {
result = result + numeral
remaining = remaining - value
}
}
result
}
}
// 为 String 添加文本处理功能
extend String {
// 反转字符串
public func reverse(): String {
let rs = this.clone().toRuneArray()
rs.reverse()
String(rs)
}
// 统计字符出现次数
public func countChar(char: Rune): Int64 {
var count = 0
for (c in this.toRuneArray()) {
if (c == char) {
count = count + 1
}
}
count
}
// 转换为驼峰命名
public func toCamelCase(): String {
if (this.size == 0) {
return ""
}
let runes = this.toRuneArray()
let result = ArrayList<Rune>()
result.add(runes[0].toUpperCase())
var capitalizeNext = false
for (i in 1..runes.size) {
let char = runes[i]
if (char == r'_' || char == r'-' || char == r' ') {
capitalizeNext = true
} else {
if (capitalizeNext) {
result.add(char.toUpperCase())
capitalizeNext = false
} else {
result.add(char)
}
}
}
result.toString()
}
}
main() {
// 测试 Int64 扩展
let number = 17
println("${number} 是质数: ${number.isPrime()}")
println("${number} 的阶乘: ${number.factorial()}")
println("${number} 的罗马数字: ${number.toRoman()}")
// 测试 String 扩展
let text = "hello_world"
println("原字符串: ${text}")
println("反转: ${text.reverse()}")
println("字符 'l' 出现次数: ${text.countChar(r'l')}")
println("驼峰命名: ${text.toCamelCase()}")
}
6.3 实现设计模式
cangjie
package cangjie_blog
// 装饰器模式示例
interface Coffee {
func cost(): Float64
func description(): String
}
class SimpleCoffee <: Coffee {
public func cost(): Float64 {
2.0
}
public func description(): String {
"简单咖啡"
}
}
// 通过扩展实现装饰器
interface CoffeeDecorator <: Coffee {
func baseCoffee(): Coffee
}
// 牛奶装饰器
class MilkDecorator {
var coffee: Coffee
public init(coffee: Coffee) {
this.coffee = coffee
}
}
extend MilkDecorator <: CoffeeDecorator {
public func baseCoffee(): Coffee {
coffee
}
public func cost(): Float64 {
baseCoffee().cost() + 0.5
}
public func description(): String {
baseCoffee().description() + " + 牛奶"
}
}
// 糖装饰器
class SugarDecorator {
var coffee: Coffee
public init(coffee: Coffee) {
this.coffee = coffee
}
}
extend SugarDecorator <: CoffeeDecorator {
public func baseCoffee(): Coffee {
coffee
}
public func cost(): Float64 {
baseCoffee().cost() + 0.2
}
public func description(): String {
baseCoffee().description() + " + 糖"
}
}
main() {
let simpleCoffee = SimpleCoffee()
println("${simpleCoffee.description()}: $${simpleCoffee.cost()}")
let milkCoffee = MilkDecorator(simpleCoffee)
println("${milkCoffee.description()}: $${milkCoffee.cost()}")
let sugarMilkCoffee = SugarDecorator(milkCoffee)
println("${sugarMilkCoffee.description()}: $${sugarMilkCoffee.cost()}")
}
7. 最佳实践与注意事项
7.1 扩展设计原则
- 单一职责原则:每个扩展应该专注于一个特定的功能领域
- 一致性原则:扩展的命名和风格应该与被扩展类型保持一致
- 可测试性原则:扩展的功能应该易于测试和验证
- 文档化原则:为扩展提供清晰的文档和示例
7.2 常见陷阱与解决方案
cangjie
// 陷阱1:过度扩展
class User {
var name: String
var email: String
public init(name: String, email: String) {
this.name = name
this.email = email
}
}
// 不好的做法:在一个扩展中添加太多不相关的方法
extend User {
func validateEmail() { /* ... */ }
func sendEmail() { /* ... */ }
func generateReport() { /* ... */ }
func backupData() { /* ... */ }
}
// 好的做法:按功能分组扩展
extend User {
func validateEmail(): Bool {
email.contains("@") && email.contains(".")
}
}
extend User {
func formatDisplayName(): String {
"用户: ${name}"
}
}
// 陷阱2:循环依赖
interface A {
func methodA(): Unit
}
interface B {
func methodB(): Unit
}
class MyClass {}
// 避免循环依赖的扩展
extend MyClass <: A {
public func methodA(): Unit {
println("实现接口A")
}
}
extend MyClass <: B {
public func methodB(): Unit {
println("实现接口B")
}
}
// 陷阱3:性能考虑
import std.collection.ArrayList
class LargeCollection<T> {
let items: ArrayList<T> = ArrayList<T>()
public func add(item: T): Unit {
items.add(item)
}
}
// 注意:扩展中的方法应该考虑性能影响
extend<T> LargeCollection<T> where T <: Equal<T> {
// 好的做法:提供高效的实现
func findFirst(predicate: (T) -> Bool): ?T {
for (item in items) {
if (predicate(item)) {
return item
}
}
None
}
// 避免:在扩展中实现低效的算法
func inefficientSearch(target: T): Bool {
// 这里应该使用更高效的搜索算法
for (item in items) {
if (item == target) {
return true
}
}
false
}
}
8. 总结
仓颉语言的扩展系统是一个强大而灵活的特性,它提供了以下核心优势:
8.1 扩展系统的优势
- 非侵入性:可以在不修改原始类型的情况下添加功能
- 类型安全:扩展遵循仓颉的类型系统规则
- 灵活性:支持泛型约束和接口实现
- 可组合性:多个扩展可以协同工作
- 可维护性:扩展的功能可以独立维护和测试
8.2 适用场景
- 为第三方库类型添加功能
- 为内置类型添加工具方法
- 实现设计模式(如装饰器、策略等)
- 提供类型适配器
- 实现功能模块化
8.3 使用建议
- 适度使用:不要过度扩展,保持代码的清晰性
- 功能分组:按功能领域组织扩展
- 性能考虑:在扩展中实现高效的算法
- 文档化:为扩展提供清晰的文档
- 测试覆盖:确保扩展功能的正确性