Swift 5动态调度未按预期进行路由

时间:2020-01-10 02:34:29

标签: swift generics swift-protocols dynamic-dispatch

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正常工作。代码流可以正确地推断类型,并且可以正确地分派到execute中的HttpExecutor的通用变体。

2是出乎意料的,因为使用泛型函数应该能够传递与内联版本相同的类型信息。

最后,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" }
}

0 个答案:

没有答案