代码之家  ›  专栏  ›  技术社区  ›  Ian Newson

Swift:协变覆盖?

  •  3
  • Ian Newson  · 技术社区  · 8 年前

    在Swift中有支持协变返回类型的方法吗?

    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()]
        }
    }
    

    重写函数会产生编译器错误,因为重写签名与基定义不完全匹配,尽管很明显,重写返回的内容仍然符合基定义的约定。

    我有什么办法实现上述目标吗?我甚至希望能为Swift 3找到答案。

    4 回复  |  直到 8 年前
        1
  •  4
  •   Grimxn    8 年前

    我不确定有必要这样做 确切地 你的要求-即。 推翻 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 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"
    
        2
  •  1
  •   Oleg Gordiichuk    8 年前

    快速使用面向协议的范例。所以根据你的要求。在您的情况下,最好使用协议和PAT。

    What are PATs.

    protocol BaseProtocol {
        //PAT's
        typealias ReturnType: BaseType
        func someFunction() -> ReturnType
    }
    
    class SomeClass : BaseProtocol {
        func someFunction() -> BaseType {  }
    }
    
        3
  •  0
  •   FelixSFD Tushar Panjwani    8 年前

    正如您已经注意到的,签名必须完全相同。

    但你可以使用 [Base] 在您的 Derived -类。

    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 (计算财产)。

    派生的 .

    let d = Derived()
    let dArray = d.test2()
    
    print((dArray[0] as! Derived).b) //Prints "B"
    
        4
  •  0
  •   brigadir    8 年前

    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