2017-09-17 106 views
2

我不确定where子句可以将通用参数限制为从某个协议继承的协议。限制从协议继承的协议泛型参数

protocol Edible {} 
protocol PetFood: Edible {} 
struct CatFood: PetFood {} 
struct Rocks {} 

func eat<T: Edible>(_ item: T) -> String { 
    return "Just ate some \(type(of: item))" 
} 

let food: CatFood = CatFood() 
eat(food) //"Just ate some CatFood" 

let moreFood: PetFood = CatFood() 
//eat(moreFood) //Cannot invoke 'eat' with an argument list of type '(PetFood)' 

func eatAnything<T>(_ item: T) -> String { 
    return "Just ate some \(type(of: item))" 
} 

eatAnything(moreFood) //This works, obviously 
eatAnything(Rocks()) //But, of course, so does this... 

有什么办法来限制eatAnything()允许协议类型,但只有那些从Edible继承?

回答

1

在你的榜样,一个泛型函数的定义并没有任何意义,因为它可以被替换为:

func eat(_ item: Edible) -> String { 
    return "Just ate some \(type(of: item))" 
} 

但如果你真的要使用通用的功能,那么你应该知道:

泛型函数的
  1. 定义

    • func eat<T: Edible>(_ item: T) -> String { ... }
    • func eat<T>(_ item: T) -> String where T: Edible { ... }
    • func eat<T: Edible>(_ item: T) -> String where T: Equatable { ... }
  2. 协议是动态的类型,所以他们使用后期绑定。在编译过程中的通用代码被转换为正常,需要早期结合

    • 早期绑定(编译时间):在运行时该变量被行使前,通常是通过一个静态的,声明性手段
    • 类型是已知
    • 延迟绑定(运行时间):类型是未知的,直到变量在运行期间被执行;通常是通过分配,但还有其他方式来强制类型;动态类型语言把这种潜在的功能
  3. 泛型函数可以是协议兼容的类型定义,但是这个功能无法通过此协议类型,因为编译器不知道是什么该类型是T。传递到泛型函数类型必须是特定类型(类,结构,枚举,...)


let a: [Int] = [1,2,3] 
let b: [CustomStringConvertible] = [1, "XYZ"] 

a.index(of: 2) // 1 
b.index(of: "XYZ") // error 
+0

嗯,肯定的 - 它只是一个简单的例子来说明这个问题。 – andyvn22

+0

@ andyvn22我更新了我的答案 –