我有以下协议和符合它的类:
protocol Foo{
typealias BazType
func bar(x:BazType) ->BazType
}
class Thing: Foo {
func bar(x: Int) -> Int {
return x.successor()
}
}
当我尝试创建一个foos数组时,我得到一个奇怪的错误:
var foos: Array<Foo> = [Thing()]
协议Foo只能用作通用约束,因为它具有 自我或相关类型要求。
好的,所以只有在它有相关的类型要求时才能使用它(它确实如此),但由于某种原因这是一个错误? WTF?!
我不确定我是否完全理解编译器试图告诉我的内容......
答案 0 :(得分:15)
让我们说,如果我们可以将Thing
的实例放入数组foos
,会发生什么?
protocol Foo {
typealias BazType
func bar(x:BazType) -> BazType
}
class Thing: Foo {
func bar(x: Int) -> Int {
return x.successor()
}
}
class AnotherThing: Foo {
func bar(x: String) -> String {
return x
}
}
var foos: [Foo] = [Thing()]
由于AnotherThing
也符合Foo
,因此我们也可以将其加入foos
。
foos.append(AnotherThing())
现在我们随机从foo
抓取foos
。
let foo = foos[Int(arc4random_uniform(UInt32(foos.count - 1)))]
我打算调用方法bar
,你能告诉我应该发送一个字符串或整数到bar
吗?
foo.bar("foo")
或foo.bar(1)
斯威夫特不能。
因此它只能用作通用约束。
什么情况需要像这样的协议?
示例:强>
class MyClass<T: Foo> {
let fooThing: T?
init(fooThing: T? = nil) {
self.fooThing = fooThing
}
func myMethod() {
let thing = fooThing as? Thing // ok
thing?.bar(1) // fine
let anotherThing = fooThing as? AnotherThing // no problem
anotherThing?.bar("foo") // you can do it
// but you can't downcast it to types which doesn't conform to Foo
let string = fooThing as? String // this is an error
}
}
答案 1 :(得分:1)
我一直在玩你的代码试图了解如何实现协议。我发现你不能将Typealias用作泛型类型,因为它只是一个别名而不是一个类型。因此,如果您在协议和类之外声明Typealias,则可以在代码中有效地使用它,而不会出现任何问题。
注意: Typealias在其声明中具有Int
类型,这样您始终可以使用别名而不是Int类型并使用其所有关联的方法和函数。< / p>
以下是我如何使其发挥作用:
typealias BazType = Int
protocol Foo{
func bar(x:BazType) -> BazType
}
class Thing: Foo {
func bar(x: BazType) -> BazType {
return x.successor()
}
}
let elements: Array<Foo> = [Thing(), Thing()]