Проблема с созданием массива AnyPokemonCreator С использованием стирающих типов

#swift

Вопрос:

У меня есть следующий код для создания массива различных создателей в Swift. Я использовал метод стирания типов, чтобы заполнить один и тот же массив разными типами создателей. Когда я пытаюсь создать список, он выдает мне сообщение об ошибке.

 error: heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional
let creators = [AnyPokemonCreator(PikachuCreator()), AnyPokemonCreator(BulbasaurCreator())]


import UIKit

struct Pikachu {
    let name: String
    let powers: [String]
}

struct Bulbasaur {
    let name: String
    let powers: [String]
}

protocol PokemanCreator {
    associatedtype Pokemon
    func create() -> Pokemon
}

struct BulbasaurCreator: PokemanCreator {
    typealias Pokemon = Bulbasaur
    
    func create() -> Pokemon {
        return Bulbasaur(name: "Bulbasaur", powers: ["Vine Whip"])
    }
}

struct PikachuCreator: PokemanCreator {
    
    typealias Pokemon = Pikachu
    
    func create() -> Pokemon {
        return Pikachu(name: "Pikachu", powers: ["Electric"])
    }
}

struct AnyPokemonCreator<Pokemon>:  PokemanCreator {
    
    private let _create: () -> Pokemon
    
    init<Creator: PokemanCreator>(_ creator: Creator) where Creator.Pokemon == Pokemon {
        _create = creator.create
    }
    
    func create() -> Pokemon {
        return _create()
    }
}

// THIS LINE GIVES ERROR
let creators = [AnyPokemonCreator(PikachuCreator()),  AnyPokemonCreator(BulbasaurCreator())]
 

Комментарии:

1. Беда в том, что ваш стирающий аппарат по-прежнему является универсальным. Разные универсальные типы-это разные типы. Таким образом, у вас нет массива одного типа элементов.

2. Вы не можете ввести-стереть функцию, которая имеет разные возвращаемые значения. Какой тип возврата creators[0].create() ? Он должен быть таким же, как тип creators[1].create() , или вы не «стерли» какие-либо типы. И у вас не может быть множества таких. Что бы вы хотели сделать с создателями? Какой код будет использовать его без использования as ? Это подскажет нам, как это исправить. (Вам, вероятно, не нужен или не нужен ластик типа здесь.)

3. Я пытаюсь стереть типы, чтобы у меня был массив создателей покемонов. Имейте в виду, что PokemonCreator-это протокол, содержащий связанный тип.

4. Этот подход не позволяет создавать массив из какого-либо создателя . Это невозможно, если только все покемоны не одного типа (обратите внимание, что в примере массив работает только потому, что все задействованные типы-электромобили; вы не можете поместить в этот массив разные типы автомобилей). Тем не менее, вам, вероятно, вообще не нужен стирающий тип. Они не являются волшебной пулей и в большинстве случаев указывают на то, что у вас есть проблема с дизайном. (Не всегда; для этого есть веские причины. Но они встречаются гораздо реже, чем люди думают.) Если вы объясните, для чего вам нужен вызывающий код, мы можем помочь.

5. Какова следующая строка кода? Когда ты пишешь for creator in creators { ... } . Что войдет в блок в вашей реальной программе?

Ответ №1:

Сначала ваш init говорит, что вы приведете аргумент, которого явно не делаете . Во-вторых, что именно вы пытаетесь сделать? Если вы хотите, чтобы кто-то придерживался протокола, просто скажите, что у меня есть то, что, согласно протоколу, мне нужно. т. е.:

 protocol PokemanCreator {
func create() -> Pokemon
}

class SomeSuperClass {
     var somethingShared: SomeValue?
}
class BulbasaurCreator: Pokemon, PokemanCreator {    
     var someBulbasaurVariable: SomeType = SomeInitialValue
     var/let name: String
     var/let powers: [String]
     static func create() -> Pokemon {
            super.init()
            return Bulbasaur(name: "Bulbasaur", powers: ["Vine Whip"])
          }
     }
 }
 

Комментарии:

1. Я хочу создать массив PokemonCreator. PokemonCreator-это протокол с соответствующим типом.

2. Я не наследую никакой структуры. Пожалуйста, взгляните на код.