Swift проделывает невероятную работу с выводом типа и оптимизацией отправки, но я столкнулся с условием, для которого я пытался найти обходной путь. Я не уверен, является ли это текущим ограничением Swift или его следует подавать как Radar (зная, что ошибки компилятора встречаются редко).
Извините за фрагмент кода, вот сокращенный код, например (подробнее после проблема) ...
/// Command executor for HTTP transports
class HttpExecutor: Executor {
func execute<T: Command>(command: T) {
print("Not a valid HttpCommand")
}
func execute<T: HttpCommand>(command: T) {
print("HttpCommand")
}
}
/// Simple function, using generic to allow the compiler to infer the same types
/// as those inferred in the constant declarations below.
func performWithExecutor<E: Executor, C: Command>(_ executor: E, command: C) {
executor.execute(command: cmd)
}
// Create command and executor
let cmd = MyCommand()
let httpExecutor = HttpExecutor()
// 1.
// Will output "HttpCommand" (expected)
httpExecutor.execute(command: cmd)
// 2.
// Will output "Not a valid HttpCommand" (unexpected)
performWithExecutor(httpExecutor, command: cmd)
// 3.
let executor: Executor = httpExecutor
// Will output "Not a valid HttpCommand" (expected, not desirable)
executor.execute(command: cmd)
В приведенном выше, 1
работает, как ожидалось. Поток кода может правильно выводить типы и может правильно отправлять вариант c generic execute
в HttpExecutor
.
2
неожиданно, поскольку использование функции generi c должно быть способен переносить ту же информацию о типе, что и встроенная версия.
Наконец, 3
несколько ожидаемо, хотя и нежелательно.
Есть какие-нибудь идеи по поводу обходных путей здесь? Я подумал об удалении типа, но похоже, что это дало бы тот же результат.
вот остаток кода ...
import Foundation
// MARK: - Command
/// Basic of all Sonos API commands
public protocol Command {
associatedtype Request: Encodable
associatedtype Response: Decodable
var name: String { get }
var message: Self.Request? { get }
}
/// A HTTP version of a command
public protocol HttpCommand: Command {
var httpMethod: String { get }
}
// MARK: - Executor
/// Command executor
protocol Executor {
func execute<T: Command>(command: T)
}
//
// MARK: -
//
/// Command to return the groups of a Sonos household
public struct MyCommand: HttpCommand {
public struct Request: Encodable { }
public struct Response: Decodable {
public var items: [String]
}
public init() { }
public var name: String = "items"
public var message: Request?
public var httpMethod: String { "GET" }
}