protocol Pokemon { associatedtype PokemonType var name: String { get } var type: PokemonType { get } } struct Electric { // something } struct Flame { // something } struct Pikachu: Pokemon { typealias PokemonType = Electric let name = "ピカチュウ" let type = Electric() } struct Hitokage: Pokemon { typealias PokemonType = Flame let name = "ヒトカゲ" let type = Flame() } struct AnyPokemon: Pokemon { typealias PokemonType = Void // Type Erasure private let _name: () -> String private let _type: () -> PokemonType init(base: X) where X: Pokemon { _name = { return base.name } _type = { return base.type } } var name: String { return _name() } var type: PokemonType { return _type() } } func battle(pokemon1: AnyPokemon, pokemon2: AnyPokemon) { print("\(pokemon1.name) vs. \(pokemon2.name)") let pokemons: [AnyPokemon] = [pokemon1, pokemon2] if let winner = pokemons.shuffled().first { print("Winner: \(winner.name)") } } // -- battle -- let pikachu: AnyPokemon = AnyPokemon(base: Pikachu()) let hitokage: AnyPokemon = AnyPokemon(base: Hitokage()) battle(pokemon1: pikachu, pokemon2: hitokage)