我一直试图让这段代码起作用
protocol Shootable
{
func shoot ()
}
protocol Shooter
{
var weapon:Shootable { get set }
}
class Gun:Shootable
{
func shoot() {
}
func someOtherMethod()
{
}
}
class Player:Shooter
{
var weapon:Gun
init ()
{
weapon = Gun()
weapon.someOtherMethod()
}
}
Run Code Online (Sandbox Code Playgroud)
但是编译器告诉我Player不符合Shooter协议.我认为这是因为玩家武器变量是Gun类型,而不是Shootable,即使Gun实现了Shootable.
但后来我改变了这个,现在它起作用了:
protocol Shooter
{
typealias Weapon:Shootable
var weapon:Weapon { get set }
}
Run Code Online (Sandbox Code Playgroud)
我不明白为什么.我认为typealiases只是给了一个类型的另一个名字,我不知道这种能力......
任何人都可以对此有所了解吗?
据我所知,声明typealias内部protocol类似于声明泛型类型。在声明中使用协议类型即声明您将仅将其用于协议声明的内容。
如果您编写以下内容,您的第一个示例将起作用:
class Player:Shooter
{
var weapon:Shootable
init ()
{
weapon = Gun()
/* weapon.someOtherMethod()
Can't use it 'cause weapon is strictly a Shootable, thus it is not meant to have any other methods than shoot()
*/
}
}
Run Code Online (Sandbox Code Playgroud)
您的第二个示例有效,因为您在协议内声明了泛型类型并要求它是符合Shootable. 您的修改利用了类型推断,因此第二个示例的以下重写可能会更清楚:
class Player:Shooter
{
typealias Weapon = Gun
var weapon:Weapon
init ()
{
weapon = Gun()
weapon.someOtherMethod()
}
}
Run Code Online (Sandbox Code Playgroud)
这里我明确声明通用协议类型别名Weapon是Gun(并且因为它符合Shootable所有就可以了)。在您的示例中,这是由编译器隐式推断的,因为没有歧义。