TypeScript
用泛型去修饰一个函数,类或者协议的变量
function identity<T>(arg: T): T {
return arg;
}
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
interface GenericIdentityFn<T> {
(arg: T): T;
}
泛型约束
有时候需要对变量类型或者行为有所约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
一个比较复杂的例子如下:
class BeeKeeper {
hasMask: boolean;
}
class ZooKeeper {
nametag: string;
}
class Animal {
numLegs: number;
}
class Bee extends Animal {
keeper: BeeKeeper;
}
class Lion extends Animal {
keeper: ZooKeeper;
}
function findKeeper<A extends Animal, K> (a: {new(): A;
prototype: {keeper: K}}): K {
return a.prototype.keeper;
}
findKeeper(Lion).nametag; // typechecks!
findKeeper这个函数定义入参a要有构造函数,返回的类型为A,A约束要继承Animal,同时a要有keeper的prototype,类型为K,如果对K有约束可继续添加K extends
Swift
常规操作,可以修饰类,结构体和函数
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
struct Stack<Element> {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
同样你在catgory中也可以使用class或者struct定义的泛型类型
extension Stack {
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
但是在协议中定义泛型类型的方式会比较特殊和TS不同
在swift语言中,协议中的泛型有个名称叫关联类型,用associatedtype修饰。其实也就是一个占位符。
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
在实际的过程中,编译器会自动推导出Item的具体类型。比如:
struct IntStack: Container {
// IntStack 的原始实现部分
var items = [Int]()
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
// Container 协议的实现部分
typealias Item = Int
mutating func append(_ item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
会自动推导出Item是Int类型,无需写typealias Item = Int这句。
泛型约束
添加约束也很简单,和TS一样。
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
// 这里是泛型函数的函数体部分
}
protocol Container {
associatedtype Item: Equatable
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
如果对协议约束有更多详细的描述,可使用where语句
func allItemsMatch<C1: Container, C2: Container>
(_ someContainer: C1, _ anotherContainer: C2) -> Bool
where C1.Item == C2.Item, C1.Item: Equatable {
// 检查两个容器含有相同数量的元素
if someContainer.count != anotherContainer.count {
return false
}
// 检查每一对元素是否相等
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// 所有元素都匹配,返回 true
return true
}
该方法约束C1和C2要满足Container协议,同时后面的where语句要求C1.Item == C2.Item,C1.Item满足Equatable协议。在category中还可以扩展约束的要求。
extension Stack where Element: Equatable {
func isTop(_ item: Element) -> Bool {
guard let topItem = items.last else {
return false
}
return topItem == item
}
}
扩展了Element必须满足Equatable协议。