仓颉之泛型 2024-08-31 周六

2024-08-30  本文已影响0人  勇往直前888

泛型概述

class List<T> { //  List<T> 中的 T 被称为类型形参
    var elem: Option<T> = None   // 对 T 的引用称为类型变元
    var tail: Option<List<T>> = None  //对 T 的引用称为类型变元
}

func sumInt(a: List<Int64>) {  } // List<Int64> 的 Int64 被称为 List 的类型实参
//  List 就是类型构造器,List<Int64> 通过 Int64 类型实参构造出了一个类型 Int64 的列表类型。

泛型函数

如果一个函数声明了一个或多个类型形参,则将其称为泛型函数。语法上,类型形参紧跟在函数名后,并用 <> 括起,如果有多个类型形参,则用“,”分离。

全局泛型函数

在声明全局泛型函数时,只需要在函数名后使用尖括号声明类型形参,然后就可以在函数形参、返回类型及函数体中对这一类型形参进行引用。

/// 该函数声明了 3 个类型形参,分别是 T1, T2, T3,其功能是把两个函数 f: (T1) -> T2, g: (T2) -> T3 复合成类型为 (T1) -> T3 的函数。
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) {
    return composition<Int64, Int64, Int64>(times2, plus10)(a)
}

main() {
  println(times2plus10(9)) // 这里,我们复合两个 (Int64) -> Int64 的函数,将 9 先乘以 2,再加 10,结果会是 28。
  return 0
}

/* 程序运行输出:
28
*/

局部泛型函数

局部函数也可以是泛型函数。

func foo(a: Int64) {
    func id<T>(a: T): T { a }

    func double(a: Int64): Int64 { a + a }

    return (id<Int64> ~> double)(a) == (double ~> id<Int64>)(a) // 这里由于 id 的单位元性质,函数 id<Int64> ~> double 和 double ~> id<Int64> 是等价的,结果是 true。
}

main() {
    println(foo(1))
    return 0
}

/* 程序运行输出:
true
*/

泛型成员函数

class、struct 与 enum 的成员函数可以是泛型的。

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)
    b.bar<String>("abc")
    c.coo<Bool>(false)
    return 0
}

/* 程序运行输出:
10
abc
false
*/
class A {
    public open func foo<T>(a: T): Unit where T <: ToString { // Error, open generic function is not allowed
        println("${a}")
    }
}
extend Int64 {
    func printIntAndArg<T>(a: T) where T <: ToString {
        println(this)
        println("${a}")
    }
}

main() {
    var a: Int64 = 12
    a.printIntAndArg<String>("twelve")
}

/* 程序运行输出:
12
twelve
*/

静态泛型函数

interface、class、struct、enum 与 extend 中可以定义静态泛型函数

import std.collection.*

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)
    return 0
}

泛型接口

泛型可以用来定义泛型接口,以标准库中定义的 Iterable 为例,它需要返回一个 Iterator 类型,这一类型是一个容器的遍历器。 Iterator 是一个泛型接口,Iterator 内部有一个从容器类型中返回下一个元素的 next 成员函数,next 成员函数返回的类型是一个需要在使用时指定的类型,所以 Iterator 需要声明泛型参数。

public interface Iterable<E> {
    func iterator(): Iterator<E>
}

public interface Iterator<E> <: Iterable<E> {
    func next(): Option<E>
}

public interface Collection<T> <: Iterable<T> {
     prop size: Int64
     func isEmpty(): Bool
}

泛型类

Map 类型中的键值对 Node 类型就可以使用泛型类来定义。
由于键与值的类型有可能不相同,且可以为任意满足条件的类型,所以 Node 需要两个类型形参 K 与 V ,K <: Hashable, K <: Equatable<K> 是对于键类型的约束,意为 K 要实现 Hashable 与 Equatable<K> 接口,也就是 K 需要满足的条件。

public open class Node<K, V> where K <: Hashable & Equatable<K> {
    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)
    }
}

泛型结构体

struct 类型的泛型与 class 是类似的

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())
    println(a.second())
}

/* 程序运行输出:
hello
0
*/

泛型枚举

在仓颉编程语言中,泛型 enum 声明的类型里被使用得最广泛的例子之一就是 Option 类型了

package core // `Option` is defined in core.

public enum Option<T> {
      Some(T)
    | None

    public func getOrThrow(): T {
        match (this) {
            case Some(v) => v
            case None => throw NoneValueException()
        }
    }
    ...
}
func safeDiv(a: Int64, b: Int64): Option<Int64> {
    var res: Option<Int64> = match (b) {
                case 0 => None
                case _ => Some(a/b)
            }
    return res
}

泛型类型的子类型关系

interface I<X, Y> { }

class C<Z> <: I<Z, Z> { }
open class C { }
class D <: C { }

interface I<X> { }

类型别名

当某个类型的名字比较复杂或者在特定场景中不够直观时,可以选择使用类型别名的方式为此类型设置一个别名。

type I64 = Int64
main() {
    type I64 = Int64 // Error, type aliases can only be defined at the top level of the source file
}

class LongNameClassA { }
type B = LongNameClassB // Error, type 'LongNameClassB' is not defined
type A = (Int64, A) // Error, 'A' refered itself

type B = (Int64, C) // Error, 'B' and 'C' are circularly refered
type C = (B, Int64)
  1. 作为类型使用
type A = B
class B {}
var a: A = B() // Use typealias A as type B
  1. 当类型别名实际指向的类型为 class、struct 时,可以作为构造器名称使用
type A = B
class B {}
func foo() { A() }  // Use type alias A as constructor of B
  1. 当类型别名实际指向的类型为 class、interface、struct 时,可以作为访问内部静态成员变量或函数的类型名:
type A = B
class B {
    static var b : Int32 = 0;
    static func foo() {}
}
func foo() {
    A.foo() // Use A to access static method in class B
    A.b
}
  1. 当类型别名实际指向的类型为 enum 时,可以作为 enum 声明的构造器的类型名
enum TimeUnit {
    Day | Month | Year
}
type Time = TimeUnit
var a = Time.Day  
var b = Time.Month   // Use type alias Time to access constructors in TimeUnit
type MyInt = Int32
MyInt(0)  // Error, no matching function for operator '()' function call

泛型别名

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

type RD<T> = RecordData<T> // 在使用时就可以用 RD<Int32> 来代指 RecordData<Int32> 类型。

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

泛型约束

泛型约束的作用是在函数、class、enum、struct 声明时明确泛型形参所具备的操作与能力。只有声明了这些约束才能调用相应的成员函数。在很多场景下泛型形参是需要加以约束的。

package core // `ToString` is defined in core.

public interface ToString {
    func toString(): String
}

func genericPrint<T>(a: T) where T <: ToString {
    println(a)
}

main() {
    genericPrint<Int64>(10)
    return 0
}

/* 程序运行输出:
10
*/
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.append(a)
    }

    public func allAnimalRuns() {
        for(a in animals) {
            println(a.run())
        }
    }
}

main() {
    var zoo: Zoo<Animal> = Zoo<Animal>()
    zoo.addAnimal(Dog())
    zoo.addAnimal(Fox())
    zoo.allAnimalRuns()
    return 0
}

/* 程序运行输出:
dog run
fox run
*/
上一篇 下一篇

猜你喜欢

热点阅读