【问题标题】:Restrict generic parameter to protocols inheriting from protocol将泛型参数限制为从协议继承的协议
【发布时间】:2018-02-25 21:10:14
【问题描述】:

我不确定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 继承的协议类型?

【问题讨论】:

    标签: swift generics inheritance protocols


    【解决方案1】:

    在您的示例中,泛型函数的定义没有任何意义,因为它可以替换为:

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

    但是如果你真的想使用泛型函数那么你应该知道:

    1. 泛型函数的定义

      • func eat&lt;T: Edible&gt;(_ item: T) -&gt; String { ... }
      • func eat&lt;T&gt;(_ item: T) -&gt; String where T: Edible { ... }
      • func eat&lt;T: Edible&gt;(_ item: T) -&gt; String where T: Equatable { ... }
    2. 协议是动态类型,因此它们使用后期绑定。泛型代码在编译期间转换为普通代码,需要提前绑定

      • 早期绑定 (编译时):在运行时执行变量之前,类型是已知的,通常通过静态、声明性方式
      • 后期绑定 (运行时):在运行时执行变量之前,类型是未知的;通常通过赋值,但还有其他方式来强制类型;动态类型语言将此称为基础功能
    3. 泛型函数可以定义为与协议兼容的类型,但此函数不能将 this 协议作为类型传递,因为编译器不知道该类型是什么 T。传递给泛型函数的类型必须是特定类型(类、结构、枚举、...)


    let a: [Int] = [1,2,3]
    let b: [CustomStringConvertible] = [1, "XYZ"]
    
    a.index(of: 2) // 1
    b.index(of: "XYZ") // error
    

    【讨论】:

    • 嗯,当然——这只是一个简单的例子来演示这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多