引言
泛型是现代编程语言中最重要的特性之一,它允许我们编写类型安全且可重用的代码。在Cangjie编程语言中,泛型系统设计得既强大又灵活,支持在函数、类、接口、结构体和枚举中使用泛型
泛型基础概念
核心术语
在开始之前,让我们理解几个关键概念:
- 类型形参(Type Parameter) :在声明时需要指定的类型,用尖括号
<>
括起 - 类型变元(Type Variable):在声明体中引用类型形参的标识符
- 类型实参(Type Argument):使用泛型时指定的具体类型
- 类型构造器(Type Constructor):需要类型实参来构造具体类型的泛型类型
基本语法
cangjie
class List<T> {
var elem: Option<T> = None
var tail: Option<List<T>> = None
}
// 泛型函数声明
func sumInt(a: List<Int64>) {}
// 使用泛型类型
var intList: List<Int64> = List<Int64>()
泛型函数
全局泛型函数
全局泛型函数是最常见的泛型使用方式,类型形参紧跟在函数名后:
cangjie
// 基本的泛型恒等函数
func id<T>(a: T): T {
return a
}
// 函数组合的泛型实现
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 * 2
}
func plus10(a: Int64): Int64 {
return a + 10
}
func times2plus10(a: Int64): Int64 {
return composition<Int64, Int64, Int64>(times2, plus10)(a)
}
main() {
println(times2plus10(9)) // 输出: 28
}
局部泛型函数
泛型函数也可以嵌套在其他函数中:
cangjie
func foo(a: Int64): Bool {
// 局部泛型函数
func id<T>(a: T): T {
return a
}
func double(a: Int64): Int64 {
return a + a
}
// 利用泛型函数的单位元性质
return (id<Int64> ~> double)(a) == (double ~> id<Int64>)(a)
}
main() {
println(foo(1)) // 输出: true
}
泛型成员函数
类、结构体和枚举的成员函数都可以是泛型的:
cangjie
class A {
func foo<T>(a: T): Unit where T <: ToString {
println("${a}")
}
}
struct B {
func bar<T>(a: T): Unit where T <: ToString {
println("${a}")
}
}
enum C {
| X | Y
func coo<T>(a: T): Unit where T <: ToString {
println("${a}")
}
}
main() {
var a = A()
var b = B()
var c = C.X
a.foo<Int64>(10) // 输出: 10
b.bar<String>("abc") // 输出: abc
c.coo<Bool>(false) // 输出: false
}
扩展中的泛型函数
可以为现有类型添加泛型成员函数:
cangjie
extend Int64 {
func printIntAndArg<T>(a: T): Unit where T <: ToString {
println(this) // 打印当前Int64值
println("${a}") // 打印泛型参数
}
}
main() {
var a: Int64 = 12
a.printIntAndArg<String>("twelve")
// 输出:
// 12
// twelve
}
静态泛型函数
静态函数也可以是泛型的:
cangjie
import std.collection.ArrayList
class ToPair {
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 a: (Int64, Int64) = ToPair.fromArray<Int64>(res)
println("${a[0]}, ${a[1]}") // 输出: 1, 2
}
泛型类
基本泛型类
泛型类允许我们创建可以处理任意类型的类:
cangjie
// 泛型节点类,用于键值对存储
open class Node<K, V> where K <: Hashable & Equatable<K> {
var key: Option<K> = Option<K>.None
var value: Option<V> = Option<V>.None
init() {}
init(key: K, value: V) {
this.key = Option<K>.Some(key)
this.value = Option<V>.Some(value)
}
func getKey(): Option<K> {
return key
}
func getValue(): Option<V> {
return value
}
}
// 使用示例
main() {
var node: Node<String, Int64> = Node<String, Int64>("age", 25)
match (node.getKey()) {
case Some(k) => println("Key: ${k}")
case None => println("No key")
}
match (node.getValue()) {
case Some(v) => println("Value: ${v}")
case None => println("No value")
}
}
静态成员限制
泛型类的静态成员不能引用类型参数:
cangjie
class A<T> {}
class B<T> {
static func foo(): Int64 {
return 1
}
// 错误:静态成员不能依赖泛型参数
// static var err1: A<T> = A<T>()
// 正确:静态成员使用具体类型
static var ok: Int64 = 1
}
main() {
B<Int32>.ok = 2
println(B<Int64>.ok) // 输出: 2
}
泛型结构体
基本泛型结构体
结构体也可以使用泛型,类似于泛型类:
cangjie
// 泛型二元组结构体
struct Pair<T, U> {
let x: T
let y: U
public init(a: T, b: U) {
x = a
y = b
}
public func first(): T {
return x
}
public func second(): U {
return y
}
}
// 使用示例
main() {
var a: Pair<String, Int64> = Pair<String, Int64>("hello", 0)
println(a.first()) // 输出: hello
println(a.second()) // 输出: 0
// 不同类型的组合
var b: Pair<Bool, Float64> = Pair<Bool, Float64>(true, 3.14)
println("${b.first()}, ${b.second()}") // 输出: true, 3.14
}
泛型枚举
Option类型
Option<T>
是Cangjie中最常用的泛型枚举类型:
cangjie
// Option类型的简化实现
enum Option<T> {
| Some(T)
| None
public func getOrThrow(): T {
match (this) {
case Some(v) => v
case None => throw NoneValueException()
}
}
public func isSome(): Bool {
match (this) {
case Some(_) => true
case None => false
}
}
public func isNone(): Bool {
return !isSome()
}
}
// 安全除法函数
func safeDiv(a: Int64, b: Int64): Option<Int64> {
var res: Option<Int64> = match (b) {
case 0 => None
case _ => Some(a / b)
}
return res
}
// 使用示例
main() {
var result1 = safeDiv(10, 2)
var result2 = safeDiv(10, 0)
match (result1) {
case Some(v) => println("10 / 2 = ${v}") // 输出: 10 / 2 = 5
case None => println("Division by zero")
}
match (result2) {
case Some(v) => println("10 / 0 = ${v}")
case None => println("Division by zero") // 输出: Division by zero
}
}
自定义泛型枚举
我们也可以定义自己的泛型枚举:
cangjie
// 表示计算结果的泛型枚举
enum Result<T, E> {
| Success(T)
| Error(E)
public func isSuccess(): Bool {
match (this) {
case Success(_) => true
case Error(_) => false
}
}
public func unwrap(): T {
match (this) {
case Success(v) => v
case Error(_) => throw NoneValueException()
}
}
}
// 使用示例
func divide(a: Int64, b: Int64): Result<Int64, String> {
if (b == 0) {
return Result<Int64, String>.Error("Division by zero")
} else {
return Result<Int64, String>.Success(a / b)
}
}
main() {
var result = divide(10, 2)
if (result.isSuccess()) {
println("Result: ${result.unwrap()}") // 输出: Result: 5
}
}
泛型接口
基本泛型接口
接口也可以使用泛型来定义通用的契约:
cangjie
// 可迭代接口
public interface Iterable<E> {
func iterator(): Iterator<E>
}
// 迭代器接口
public interface Iterator<E> <: Iterable<E> {
func next(): Option<E>
func hasNext(): Bool
}
// 集合接口
public interface Collection<T> <: Iterable<T> {
prop size: Int64
func isEmpty(): Bool
func add(item: T): Unit
func remove(item: T): Bool
}
// 实现示例
class ArrayList<T> <: Collection<T> {
// 假定这里是底层C函数的数组
private let items: Array<T> = Array<T>()
public prop size: Int64 {
get() {
return items.size
}
}
public func isEmpty(): Bool {
return items.isEmpty()
}
public func add(item: T): Unit {
// items.push(item)
}
public func remove(item: T): Bool {
// 简化实现
return false
}
public func iterator(): Iterator<T> {
return ArrayListIterator<T>(items)
}
}
// 迭代器实现
class ArrayListIterator<T> <: Iterator<T> {
private var items: Array<T>
private var index: Int64 = 0
init(items: Array<T>) {
this.items = items
}
public func next(): Option<T> {
if (index < items.size) {
var item = items[index]
index = index + 1
return Option<T>.Some(item)
} else {
return Option<T>.None
}
}
public func hasNext(): Bool {
return index < items.size
}
public func iterator(): Iterator<T> {
return this
}
}
泛型约束
接口约束
泛型约束允许我们限制类型参数必须实现特定的接口:
cangjie
// 可打印接口
public interface ToString {
func toString(): String
}
// 可比较接口
public interface Comparable<T> {
func compareTo(other: T): Int32
}
// 使用约束的泛型函数
func genericPrint<T>(a: T): Unit where T <: ToString {
println(a.toString())
}
// 泛型比较函数
func max<T>(a: T, b: T): T where T <: Comparable<T> {
if (a.compareTo(b) > 0) {
return a
} else {
return b
}
}
// 实现接口的类型
class Person <: ToString & Comparable<Person> {
var name: String
var age: Int64
init(name: String, age: Int64) {
this.name = name
this.age = age
}
public func toString(): String {
return "Person(name=${name}, age=${age})"
}
public func compareTo(other: Person): Int32 {
if (this.age < other.age) {
return -1
} else if (this.age > other.age) {
return 1
} else {
return 0
}
}
}
// 使用示例
main() {
var person1 = Person("Alice", 25)
var person2 = Person("Bob", 30)
genericPrint<Person>(person1) // 输出: Person(name=Alice, age=25)
var older = max<Person>(person1, person2)
println("Older person: ${older.name}") // 输出: Older person: Bob
}
类类型约束
我们也可以使用具体的类来约束泛型类型:
cangjie
import std.collection.ArrayList
// 动物基类
abstract class Animal {
public func run(): String
public func makeSound(): String
}
// 狗类
class Dog <: Animal {
public func run(): String {
return "dog run"
}
public func makeSound(): String {
return "woof"
}
}
// 狐狸类
class Fox <: Animal {
public func run(): String {
return "fox run"
}
public func makeSound(): String {
return "yip"
}
}
// 动物园类,只能容纳动物
class Zoo<T> where T <: Animal {
let animals: ArrayList<Animal> = ArrayList<Animal>()
public func addAnimal(a: T): Unit {
animals.add(a)
}
public func allAnimalRuns(): Unit {
for (a in animals) {
println(a.run())
}
}
public func allAnimalSounds(): Unit {
for (a in animals) {
println(a.makeSound())
}
}
}
// 使用示例
main() {
let zoo: Zoo<Animal> = Zoo<Animal>()
zoo.addAnimal(Dog())
zoo.addAnimal(Fox())
println("Animals running:")
zoo.allAnimalRuns()
// 输出:
// Animals running:
// dog run
// fox run
println("Animals making sounds:")
zoo.allAnimalSounds()
// 输出:
// Animals making sounds:
// woof
// yip
}
多重约束
一个类型参数可以同时满足多个约束:
cangjie
// 可序列化接口
public interface Serializable {
func serialize(): String
}
// 可反序列化接口
public interface Deserializable<T> {
static func deserialize(data: String): T
}
// 同时满足多个约束的泛型函数
func processData<T>(data: T): String where T <: ToString & Serializable {
let str = data.toString()
let serialized = data.serialize()
return "String: ${str}, Serialized: ${serialized}"
}
// 实现多个接口的类型
class DataItem <: ToString & Serializable {
let id: Int64
let content: String
init(id: Int64, content: String) {
this.id = id
this.content = content
}
public func toString(): String {
return "DataItem(id=${id}, content=${content})"
}
public func serialize(): String {
return "${id}:${content}"
}
}
// 使用示例
main() {
let item = DataItem(1, "Hello World")
let result = processData<DataItem>(item)
println(result)
// 输出: String: DataItem(id=1, content=Hello World), Serialized: 1:Hello World
}
泛型子类型关系
基本概念
在Cangjie中,泛型类型的子类型关系遵循特定的规则:
cangjie
// 泛型接口
interface I<X, Y> { }
// 泛型类实现泛型接口
class C<Z> <: I<Z, Z> { }
// 使用示例
main() {
// 根据 class C<Z> <: I<Z, Z>,我们知道:
// C<Bool> <: I<Bool, Bool>
// C<Int64> <: I<Int64, Int64>
var c1: C<Bool> = C<Bool>()
var c2: C<Int64> = C<Int64>()
// 这些类型关系是成立的
}
型变规则
Cangjie中的用户自定义泛型类型在其类型参数处是不型变的:
cangjie
open class C { }
class D <: C { }
class I<X> { }
main() {
// 即使 D <: C 成立,I<D> <: I<C> 也不成立
// 这是因为Cangjie中的泛型类型是不型变的
var d: D = D()
var c: C = d // 这是允许的
// 但是泛型类型之间不能这样转换
var i1: I<D> = I<D>()
// var i2: I<C> = i1 // 这会报错
}
内建类型的型变
内建类型遵循不同的型变规则:
cangjie
open class C {}
class D <: C {}
main() {
// 元组类型对其每个元素类型都是协变的
var tuple1: (D, D) = (D(), D())
var tuple2: (C, C) = tuple1 // 这是允许的
// 函数类型在其入参类型处是逆变的,在返回类型处是协变的
var func1: (C) -> D = {c: C => D()}
var func2: (D) -> C = func1 // 这是允许的
}
类型别名
基本类型别名
类型别名可以为复杂类型提供更简洁的名称:
cangjie
// 基本类型别名
type I64 = Int64
type F64 = Float64
type Str = String
// 使用示例
main() {
var a: I64 = 42
var b: F64 = 3.14
var c: Str = "Hello"
println("${a}, ${b}, ${c}")
}
泛型类型别名
类型别名也可以使用泛型:
cangjie
// 泛型结构体
struct RecordData<T> {
var a: T
public init(x: T) {
a = x
}
}
// 泛型类型别名
type RD<T> = RecordData<T>
type IntRecord = RecordData<Int64>
type StringRecord = RecordData<String>
// 使用示例
main() {
var struct1: RD<Int32> = RecordData<Int32>(2)
var struct2: IntRecord = RecordData<Int64>(42)
var struct3: StringRecord = RecordData<String>("Hello")
println("${struct1.a}, ${struct2.a}, ${struct3.a}")
// 输出: 2, 42, Hello
}
类型别名的使用场景
类型别名有多种使用方式:
cangjie
// 1. 作为类型使用
type A = B
class B {
static func staticMethod() {}
}
var a1: A = B()
// 2. 作为构造器名称使用
type C = B
func foo() { C() }
// 3. 访问静态成员
type D = B
func bar() {
D.staticMethod() // 如果B有静态方法
}
// 4. 枚举构造器
enum TimeUnit {
| Day | Month | Year
}
type Time = TimeUnit
var day = Time.Day
var month = Time.Month
实际应用案例
通用容器实现
让我们实现一个通用的栈容器:
cangjie
import std.collection.ArrayList
// 泛型栈接口
interface Stack<T> {
func push(item: T): Unit
func pop(): Option<T>
func peek(): Option<T>
func isEmpty(): Bool
func size(): Int64
}
// 基于ArrayList的栈实现
class ArrayStack<T> <: Stack<T> {
private var items: ArrayList<T> = ArrayList<T>()
public func push(item: T): Unit {
items.add(item)
}
public func pop(): Option<T> {
if (isEmpty()) {
return Option<T>.None
} else {
var size = items.size
var item = items[size - 1]
items.remove(at: size - 1)
return Option<T>.Some(item)
}
}
public func peek(): Option<T> {
if (isEmpty()) {
return Option<T>.None
} else {
var size = items.size
return Option<T>.Some(items[size - 1])
}
}
public func isEmpty(): Bool {
return items.size == 0
}
public func size(): Int64 {
return items.size
}
}
// 使用示例
main() {
var intStack: ArrayStack<Int64> = ArrayStack<Int64>()
// 压入元素
intStack.push(1)
intStack.push(2)
intStack.push(3)
println("Stack size: ${intStack.size()}")
// 弹出元素
while (!intStack.isEmpty()) {
match (intStack.pop()) {
case Some(item) => println("Popped: ${item}")
case None => println("Stack is empty")
}
}
}
通用算法实现
实现一些通用的算法函数:
cangjie
import std.collection.ArrayList
// 通用查找函数
func find<T>(items: Array<T>, predicate: (T) -> Bool): Option<T> {
for (item in items) {
if (predicate(item)) {
return Option<T>.Some(item)
}
}
return Option<T>.None
}
// 通用过滤函数
func filter<T>(items: Array<T>, predicate: (T) -> Bool): Array<T> {
let result: ArrayList<T> = ArrayList<T>()
for (item in items) {
if (predicate(item)) {
result.add(item)
}
}
return result.toArray()
}
// 通用映射函数
func map<T, U>(items: Array<T>, transform: (T) -> U): Array<U> {
let result: ArrayList<U> = ArrayList<U>()
for (item in items) {
result.add(transform(item))
}
return result.toArray()
}
// 使用示例
main() {
let numbers: Array<Int64> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 查找第一个偶数
var firstEven = find<Int64>(numbers, { n: Int64 => n % 2 == 0 })
match (firstEven) {
case Some(n) => println("First even number: ${n}")
case None => println("No even numbers found")
}
// 过滤出所有偶数
var evenNumbers = filter<Int64>(numbers, { n: Int64 => n % 2 == 0 })
println("Even numbers: ${evenNumbers}")
// 将每个数字平方
var squaredNumbers = map<Int64, Int64>(numbers, { n: Int64 => n * n })
println("Squared numbers: ${squaredNumbers}")
}
通用数据结构
实现一个通用的二叉树:
cangjie
import std.collection.ArrayList
// 泛型二叉树节点
class TreeNode<T> {
var value: T
var left: Option<TreeNode<T>> = Option<TreeNode<T>>.None
var right: Option<TreeNode<T>> = Option<TreeNode<T>>.None
init(value: T) {
this.value = value
}
}
// 泛型二叉树
class BinaryTree<T> where T <: Comparable<T> {
var root: Option<TreeNode<T>> = Option<TreeNode<T>>.None
public func insert(value: T): Unit {
root = insertRecursive(root, value)
}
private func insertRecursive(node: Option<TreeNode<T>>, value: T): Option<TreeNode<T>> {
match (node) {
case None => return Option<TreeNode<T>>.Some(TreeNode<T>(value))
case Some(n) =>
if (value.compare(n.value) == Ordering.LT) {
n.left = insertRecursive(n.left, value)
} else {
n.right = insertRecursive(n.right, value)
}
return Option<TreeNode<T>>.Some(n)
}
}
public func inorderTraversal(): Array<T> {
let result: ArrayList<T> = ArrayList<T>()
inorderRecursive(root, result)
return result.toArray()
}
private func inorderRecursive(node: Option<TreeNode<T>>, result: ArrayList<T>): Unit {
match (node) {
case None => return
case Some(n) =>
inorderRecursive(n.left, result)
result.add(n.value)
inorderRecursive(n.right, result)
}
}
}
// 使用示例
main() {
let tree: BinaryTree<Int64> = BinaryTree<Int64>()
// 插入元素
tree.insert(5)
tree.insert(3)
tree.insert(7)
tree.insert(1)
tree.insert(9)
// 中序遍历
let result = tree.inorderTraversal()
println("Inorder traversal: ${result}")
// 输出: Inorder traversal: [1, 3, 5, 7, 9]
}