Swift:协变覆盖?
Swift: Covariant overrides?
有什么方法可以在 Swift 中支持协变 return 类型吗?
例如,我想支持以下场景:
class Animal {}
class Dog : Animal{}
class Cat : Animal {}
class AnimalResidency{
func getAllAnimals() -> Array<Animal> {
return []
}
}
class Cattery : AnimalResidency{
override func getAllAnimals() -> Array<Cat> {
return [Cat(), Cat()]
}
}
class DogKennel : AnimalResidency {
override func getAllAnimals() -> Array<Dog> {
return [Dog(), Dog(), Dog(), Dog()]
}
}
覆盖的函数会产生编译器错误,因为覆盖签名与基本定义不完全匹配,即使很明显看到被覆盖 return 编辑的内容仍然符合基本的约定定义。
请问有什么方法可以达到上面的效果吗?我什至很感激 Swift 3.
的回答
正如您已经注意到的,签名必须完全相同。
但是您可以使用 [Base]
作为 return 输入您的 Derived
-class。
class Base {
var a = "A" //just a property to check if you can access properties of this class
var test: [Base] {
return [self]
}
func test2() -> [Base] {
return [self]
}
}
class Derived: Base {
var b = "B" //just a property to check if you can access properties of this class
override var test: [Base] {
return [self]
}
override func test2() -> [Base] {
return [self]
}
}
您可以使用 test2()
或 test
(计算得到的 属性)。
在访问存储在数组中的对象的 属性 之前,必须将其转换为 Derived
。
let d = Derived()
let dArray = d.test2()
print((dArray[0] as! Derived).b) //Prints "B"
Swift 使用面向协议的范例。所以根据你的要求。在你的情况下,最好使用协议和 PAT。
protocol BaseProtocol {
//PAT's
typealias ReturnType: BaseType
func someFunction() -> ReturnType
}
class SomeClass : BaseProtocol {
func someFunction() -> BaseType { }
}
如 FelixSFD 的回答所述,您的目标与面向接口的范式冲突。 HeadOffice
应该使用 Office
的接口,例如:
let staff: [Office] = [Office(), HeadOffice()]
for person in staff {
// every `person` responds to `Office` interface
}
在你的情况下,我建议使用泛型,因为它们是为这类事情而设计的:
func getAllStaff<T>(obj: T) -> Array<T?> {
return [obj]
}
您还可以将 getAllStaff
实现为 class 的方法,具体取决于您的需要...
我不确定是否有必要 完全 你问的 - 即 覆盖 getAllAnimals
而不是超载.使用泛型是一种可能的解决方案 - 看看这是否适合您:
class Animal { var description: String { return "Animal" } }
class Dog : Animal { override var description: String { return "Dog" } }
class Cat : Animal { override var description: String { return "Cat" } }
class AnimalResidency<T: Animal>{
func getAllAnimals<T>() -> Array<T> {
return []
}
}
class Cattery : AnimalResidency<Cat> {
func getAllAnimals() -> Array<Cat> {
return [Cat()]
}
}
class DogKennel : AnimalResidency<Dog> {
func getAllAnimals() -> Array<Dog> {
return [Dog(), Dog()]
}
}
let c = Cattery()
c.getAllAnimals().first?.description // "Cat"
let d = DogKennel()
d.getAllAnimals().first?.description // "Dog"
然而,我自己的想法不会使用两个并行的 class 层次结构,而是尝试更像这样的东西...
class Animal {
var description: String { return "Animal" }
required init() {}
}
class Dog : Animal {
override var description: String { return "Dog" }
}
class Cat : Animal {
override var description: String { return "Cat" }
}
extension Animal {
class func home() -> [Animal] {
return [self.init()]
}
}
let c = Cat.home().first?.description // "Cat"
let d = Dog.home().first?.description // "Dog"
有什么方法可以在 Swift 中支持协变 return 类型吗?
例如,我想支持以下场景:
class Animal {}
class Dog : Animal{}
class Cat : Animal {}
class AnimalResidency{
func getAllAnimals() -> Array<Animal> {
return []
}
}
class Cattery : AnimalResidency{
override func getAllAnimals() -> Array<Cat> {
return [Cat(), Cat()]
}
}
class DogKennel : AnimalResidency {
override func getAllAnimals() -> Array<Dog> {
return [Dog(), Dog(), Dog(), Dog()]
}
}
覆盖的函数会产生编译器错误,因为覆盖签名与基本定义不完全匹配,即使很明显看到被覆盖 return 编辑的内容仍然符合基本的约定定义。
请问有什么方法可以达到上面的效果吗?我什至很感激 Swift 3.
的回答正如您已经注意到的,签名必须完全相同。
但是您可以使用 [Base]
作为 return 输入您的 Derived
-class。
class Base {
var a = "A" //just a property to check if you can access properties of this class
var test: [Base] {
return [self]
}
func test2() -> [Base] {
return [self]
}
}
class Derived: Base {
var b = "B" //just a property to check if you can access properties of this class
override var test: [Base] {
return [self]
}
override func test2() -> [Base] {
return [self]
}
}
您可以使用 test2()
或 test
(计算得到的 属性)。
在访问存储在数组中的对象的 属性 之前,必须将其转换为 Derived
。
let d = Derived()
let dArray = d.test2()
print((dArray[0] as! Derived).b) //Prints "B"
Swift 使用面向协议的范例。所以根据你的要求。在你的情况下,最好使用协议和 PAT。
protocol BaseProtocol {
//PAT's
typealias ReturnType: BaseType
func someFunction() -> ReturnType
}
class SomeClass : BaseProtocol {
func someFunction() -> BaseType { }
}
如 FelixSFD 的回答所述,您的目标与面向接口的范式冲突。 HeadOffice
应该使用 Office
的接口,例如:
let staff: [Office] = [Office(), HeadOffice()]
for person in staff {
// every `person` responds to `Office` interface
}
在你的情况下,我建议使用泛型,因为它们是为这类事情而设计的:
func getAllStaff<T>(obj: T) -> Array<T?> {
return [obj]
}
您还可以将 getAllStaff
实现为 class 的方法,具体取决于您的需要...
我不确定是否有必要 完全 你问的 - 即 覆盖 getAllAnimals
而不是超载.使用泛型是一种可能的解决方案 - 看看这是否适合您:
class Animal { var description: String { return "Animal" } }
class Dog : Animal { override var description: String { return "Dog" } }
class Cat : Animal { override var description: String { return "Cat" } }
class AnimalResidency<T: Animal>{
func getAllAnimals<T>() -> Array<T> {
return []
}
}
class Cattery : AnimalResidency<Cat> {
func getAllAnimals() -> Array<Cat> {
return [Cat()]
}
}
class DogKennel : AnimalResidency<Dog> {
func getAllAnimals() -> Array<Dog> {
return [Dog(), Dog()]
}
}
let c = Cattery()
c.getAllAnimals().first?.description // "Cat"
let d = DogKennel()
d.getAllAnimals().first?.description // "Dog"
然而,我自己的想法不会使用两个并行的 class 层次结构,而是尝试更像这样的东西...
class Animal {
var description: String { return "Animal" }
required init() {}
}
class Dog : Animal {
override var description: String { return "Dog" }
}
class Cat : Animal {
override var description: String { return "Cat" }
}
extension Animal {
class func home() -> [Animal] {
return [self.init()]
}
}
let c = Cat.home().first?.description // "Cat"
let d = Dog.home().first?.description // "Dog"