我试图在 swift 中设计一个抽象类,其中一个函数采用该类的子类的实例。但是,我想将参数的类型指定为抽象类的名称,因为我不知道将传递该类的哪个子级。示例代码:
protocol Character {
...
}
extension Character {
...
mutating func fight(target: inout Character) {
target.hp -= 10
}
}
struct Warrior: Character {
...
}
struct Mage: Character {
...
}
foo = Warrior()
bar = Mage()
foo.fight(target: bar)
Run Code Online (Sandbox Code Playgroud)
在这段代码中,我得到了错误:Inout argument could be set to a value with a type other than 'Mage', use a value declared as type 'Character' instead,这意味着编译器无法识别 Mage 实现了 Character,因此是字符类型。我该如何解决这个问题?
我假设您的代码如下所示:
extension Character {
mutating func fight(target: inout Character) {
target.hp -= 10
}
}
var foo = Warrior()
var bar = Mage()
foo.fight(target: &bar)
Run Code Online (Sandbox Code Playgroud)
问题是您的bar变量被推断为类型Mage,您不能将其作为 inout 参数传递给采用Character.
要了解为什么存在此限制,请想象您的fight函数具有以下实现:
mutating func fight(target: inout Character) {
target = Warrior()
}
Run Code Online (Sandbox Code Playgroud)
如果将一个类型的变量传递Mage给该函数是有效的,那么您将一个类型的值分配给一个显然无法工作的类型Warrior的变量Mage。
如果要传递bar给函数,则需要将其声明为:
var bar: Character = Mage()
Run Code Online (Sandbox Code Playgroud)
另一种方法是使您的fight函数通用,它可以与您的原始调用代码一起使用,但会有其他限制:
mutating func fight<T: Character>(target: inout T) {
target.hp -= 10
}
Run Code Online (Sandbox Code Playgroud)