Статический метод базового класса возвращает тип подкласса в Swift - PullRequest
0 голосов
/ 26 октября 2019

Я хочу иметь статический метод базового класса, который возвращает массив типа подкласса. Вот моя текущая реализация. Это работает, но у меня есть небольшая проблема с ним.

class Animal {
    required init() { }
    public static func generateMocks<T: Animal>() -> [T] {
        var mocks: [T] = []
        // some implementation goes here...
        for _ in 0..<10 {
            mocks.append( T() )
        }
        //
        return mocks
    }
}


let myMockAnimals: [Animal] = Animal.generateMocks() // this gives me type [Animal]

class Dog: Animal {
    // dog things
    var isCute = true
}

let myMockDogs: [Dog] = Dog.generateMocks() // this gives me type [Dog]
print(myMockDogs.first?.isCute) // true

/* My problem is that it is very annoying to have to declare my
   myMockDogs variable as type "[Dog]". I would like it to
   automatically infer this type. Like this: */

let myMockDogs2 = Dog.generateMocks() // oh no! It gives me type [Animal]
print(myMockDogs2.first?.isCute) // error! Value of type 'Animal' has no member 'isCute'
if let dog = myMockDogs2.first! as Dog { // error! 'Animal' is not convertible to 'Dog';
    print(dog)
}

Так что моя общая статическая функция generateMocks способна вернуть правильный подкласс, когда я указываю ожидаемый тип объекта, например let myMockDogs2: [Dog] =..., но когда я отбрасываю явный тип, который я ожидаю, как в let myMockDogs2 =..., он внезапно возвращается к использованию Animal в качестве типа, используемого для универсальной функции, в результате чего получается массив [Animal].

Есть ли способ изменить функцию generateMocks, которая заставит let myMockDogs2 = Dog.generateMocks() автоматически использовать тип Dog для общего T?

Вы можете скопировать этот код в игровую площадкуслишком! Это работает там! Я действительно боюсь, что нет решения, но, возможно, у гения Свифта есть идея.

1 Ответ

1 голос
/ 26 октября 2019

Возможным решением является расширение протокола

protocol Animal {
    init()
    static func generateMocks() -> [Self]
}

extension Animal {
    static func generateMocks() -> [Self] {
        var mocks: [Self] = []
        // some implementation goes here...
        for _ in 0..<10 {
            mocks.append( Self() )
        }
        //
        return mocks
    }
}

struct Dog: Animal {
    // dog things
    var isCute = true
}

let myMockDogs = Dog.generateMocks()
print(myMockDogs.first?.isCute) // true
...