仓颉语言中的泛型系统:概述、函数、接口与类
·
仓颉语言中的泛型系统:概述、函数、接口与类
一、泛型概述
1.1 泛型核心概念
参数化类型是仓颉泛型的核心,它允许在声明时使用未知类型,在使用时指定具体类型。这种机制在容器类型中尤为常见,如Array<T>
和Set<T>
。泛型通过三个关键概念实现:
- 类型形参:声明时的占位符类型(如
class List<T>
中的T
) - 类型变元:在声明体中引用类型形参(如
Option<T>
中的T
) - 类型实参:使用泛型时指定的具体类型(如
List<Int64>
中的Int64
)
1.2 泛型声明位置
仓颉支持在多种结构中使用泛型:
// 泛型函数
func id<T>(a: T): T { return a }
// 泛型类
class List<T> {
var elem: Option<T>
}
// 泛型接口
interface Iterable<E> {
func iterator(): Iterator<E>
}
// 泛型结构体
struct Pair<T1, T2> {
let x: T1
let y: T2
}
// 泛型枚举
enum Option<T> {
| Some(T)
| None
}
1.3 类型构造器
需要零个或多个类型作为实参的类型称为类型构造器。例如List
是类型构造器,List<Int64>
是通过Int64
构造出的具体类型。
二、泛型函数
2.1 全局泛型函数
在函数名后声明类型形参:
func composition<T1, T2, T3>(f: (T1) -> T2, g: (T2) -> T3): (T1) -> T3 {
return { x: T1 => g(f(x)) }
}
此函数将两个函数组合成新函数,支持任意输入/输出类型组合。
2.2 局部泛型函数
可在其他函数内定义泛型函数:
func foo(a: Int64) {
func id<T>(a: T): T { a }
println(id<Int64>(10))
}
2.3 成员泛型函数
类、结构体和枚举的成员函数可以是泛型的:
class A {
func foo<T>(a: T) where T <: ToString {
println("${a}")
}
}
2.4 静态泛型函数
支持在类、结构体等类型中定义静态泛型函数:
class ToPair {
public static func fromArray<T>(l: ArrayList<T>): (T, T) {
return (l[0], l
}
}
2.5 泛型约束
使用where
子句约束类型参数:
func genericPrint<T>(a: T) where T <: ToString {
println(a.toString())
}
此函数要求T
必须实现ToString
接口。
三、泛型接口
3.1 基本定义
泛型接口允许在接口中使用类型参数:
public interface Iterable<E> {
func iterator(): Iterator<E>
}
public interface Iterator<E> <: Iterable<E> {
func next(): Option<E>
}
3.2 接口继承
泛型接口可继承其他接口:
public interface Collection<T> <: Iterable<T> {
prop size: Int64
func isEmpty(): Bool
}
3.3 实现约束
实现泛型接口时可添加额外约束:
class Cell<T> {}
extend <T> Cell<T> <: ToString where T <: ToString {
public func toString(): String {
"Cell(value = ${value})"
}
}
3.4 静态成员抽象
通过泛型约束实现静态成员抽象:
interface NamedType {
static func typename(): String
}
func printTypeName<T>() where T <: NamedType {
println("Type: ${T.typename()}")
}
四、泛型类
4.1 基本定义
类声明时指定类型参数:
public class Node<K, V> where K <: Hashable & Equatable<K> {
public var key: Option<K>
public var value: Option<V>
}
4.2 静态成员限制
泛型类的静态成员有特殊限制:
class B<T> {
static var err1: A<T> = A<T>() // 错误!静态成员不能依赖泛型参数
static var ok: Int64 = 1 // 允许
}
因为静态成员在内存中共享,不能依赖具体类型实例化。
4.3 继承与子类型
泛型类可继承其他类或接口:
class Zoo<T> where T <: Animal {
var animals: ArrayList<Animal>
}
4.4 构造器约束
泛型类可约束类型参数:
class Node<K, V> where K <: Hashable & Equatable<K> {
// K必须实现Hashable和Equatable接口
}
五、泛型约束详解
5.1 接口约束
最常见的约束类型:
func sort<T>(list: ArrayList<T>) where T <: Comparable<T>
5.2 类类型约束
要求类型是特定类的子类:
class Zoo<T> where T <: Animal {
// T必须是Animal的子类
}
5.3 多约束组合
使用&
连接多个约束:
func process<T>(item: T) where T <: Serializable & Cloneable
5.4 约束继承
子类可添加额外约束:
class SpecialList<T> <: List<T> where T <: Serializable
六、高级泛型特性
6.1 泛型枚举
Option<T>
是最常用的泛型枚举:
public enum Option<T> {
| Some(T)
| None
}
6.2 泛型类型推导
编译器可自动推断类型实参:
let list = ArrayList([1, 2, 3]) // 自动推导为ArrayList<Int64>
6.3 泛型反射
运行时获取泛型类型信息:
let typeInfo = TypeInfo.of<ArrayList<Int64>>()
6.4 泛型测试
使用@Types
宏测试泛型:
@Test
@Types[T in <Int64, String>]
class TestClass<T> {
@TestCase
func testMethod() { ... }
}
七、最佳实践
7.1 命名规范
- 单类型参数使用
T
- 多类型参数使用
K
,V
(键值)或T1
,T2
- 约束明确的参数使用有意义的名称(如
TElement
)
7.2 约束设计
- 仅添加必要的约束
- 优先使用接口约束而非类约束
- 避免过度约束限制泛型灵活性
7.3 错误处理
- 明确处理约束不满足的情况
- 使用
Option<T>
处理可能缺失的值 - 为泛型函数提供清晰的错误信息
结论
仓颉语言的泛型系统提供了强大的抽象能力,通过参数化类型实现了代码复用与类型安全。关键要点包括:
- 灵活的应用范围:支持函数、类、接口、结构体和枚举
- 严密的类型约束:通过
where
子句确保类型安全 - 静态成员限制:避免泛型参数影响静态成员
- 丰富的标准库应用:容器类型完全基于泛型实现
- 高级特性支持:反射、测试等场景的深度集成
仓颉的泛型设计平衡了灵活性与安全性,使开发者能够构建高度抽象且类型安全的代码库。掌握泛型的使用约束和最佳实践,是发挥仓颉语言优势的关键。
更多推荐
所有评论(0)