2016-09-05 5 views
3

Swift에서 공변 반환 유형을 지원하는 방법이 있습니까? 그것을보고 분명하더라도, 오버라이드 (override) 서명이 정확히 기본 정의와 일치하지 않기 때문에스위프트 : 공변량을 재정의 하시겠습니까?

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

재정의 FUNC은 컴파일러 오류가 발생합니다 :

예를 들어, 나는 다음과 같은 시나리오를 지원하고 싶습니다 오버라이드 (override)에 의해 반환 된 내용은 여전히 ​​기본 정의의 계약을 충족합니다.

나를 달성 할 수있는 방법이 있습니까? Swift 3에 대한 답변도 감사 할 것입니다.

답변

4

정확히 무엇이 필요한지 잘 모르겠습니다. 정확히 무엇을 물으시겠습니까? 예 : 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" 
0

이미 알고 계시다시피, 서명은 완전히 동일해야합니다.

그러나 Derived -class에서 반환 유형으로 [Base]을 사용할 수 있습니다.

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" 
+0

이 접근법은'b'에 접근하기 위해'Derived '로 강제 변환해야하는 인쇄 라인을 분해합니다. OP는 파생 클래스가 super의 반환 유형에서 파생 된 특정 유형을 반환하도록하여 캐스팅이 필요하지 않도록합니다. –

1

스위프트 사용 프로토콜 지향 패러다임. 그래서 당신을 기반으로 요청합니다. 프로토콜 및 PAT를 사용하는 것이 좋습니다.

What are PATs.

인터페이스 중심의 패러다임으로 목표 충돌 대답 FelixSFD의에서 언급 한 바와 같이
protocol BaseProtocol { 
    //PAT's 
    typealias ReturnType: BaseType 
    func someFunction() -> ReturnType 
} 

class SomeClass : BaseProtocol { 
    func someFunction() -> BaseType { } 
} 
+1

죄송합니다. 게시 한 예에서 공분산의 증거를 볼 수 없습니다. 공분산이 어디에 적용되는지 알려줄 수 있습니까? –

0

.

func getAllStaff<T>(obj: T) -> Array<T?> { 
    return [obj] 
} 

또한의 방법으로 getAllStaff을 구현할 수 : 그들은 사물의 같은 종류의 설계 때문에 제네릭을 사용하도록 제안 할 것입니다 귀하의 경우에는

let staff: [Office] = [Office(), HeadOffice()] 
for person in staff { 
    // every `person` responds to `Office` interface 
} 

: HeadOfficeOffice의 인터페이스, 예를 사용해야합니다 수업에 따라 ...

관련 문제