【问题标题】:Cannot convert value of type '(T) -> Void'无法转换类型“(T)-> Void”的值
【发布时间】:2017-10-10 18:24:38
【问题描述】:

例子:

struct Wrapper<T> {
    var key: Int = 0
    var listeners: [Int: (T) -> Void] = Dictionary()

    mutating func add(_ handler:@escaping (T) -> Void) {
        self.key += 1
        self.listeners[self.key] = handler
    }

    func get(key: Int) -> (T) -> Void {
        return self.listeners[key]!
    }
}

测试协议:

protocol CommonProtocol {

}

创建测试类包装器的类

class C {
    var wrapper: Wrapper = Wrapper<CommonProtocol>()

    func add<T: CommonProtocol>(_ handler: @escaping (T) -> Void) {
        self.wrapper.add(handler) //Cannot convert value of type '(T) -> Void' to expected argument type '(CommonProtocol) -> Void'
    }
}

Image with error

我得到错误:

Cannot convert value of type '(T) -> Void' to expected argument type '(CommonProtocol) -> Void'

问题:

为什么 (T) -&gt; Void 不能转换为 (CommonProtocol) -&gt; VoidT 被明确声明为&lt;T: CommonProtocol&gt;

这是我的第一个问题,如果您有任何建议,请随时与我联系

【问题讨论】:

  • 编译器相当正确; (T) -&gt; Void 不是 (CommonProtocol) -&gt; Void。假设String : CommonProtocolInt : CommonProtocol。用String 替换T。如果(T) -&gt; Void 可以转换为(CommonProtocol) -&gt; Void,那么我们可以将Int 传递给String 参数。
  • @Hamish,你是对的,但是如果我将函数 add 更改为:func add(_ handler: @escaping (CommonProtocol) -&gt; Void) 我没有收到任何错误,看起来如果问题是你所说的,这一定是一个错误还有
  • 为什么你会认为这是一个错误?你现在将 (CommonProtocol) -&gt; Void 传递给期望 (CommonProtocol) -&gt; Void 的东西——这是完全合法的。

标签: swift generics closures


【解决方案1】:

您无需将func add 设为通用。 当您在 func add&lt;T: CommonProtocol&gt;... 中指定时,您明确告诉编译器您的函数接受所有 inherit CommonProtocol 但您的 Wrapper 指定接受 CommonProtocol 而不是继承类型的类型。

解决方案

类型擦除类 C:

Class C<T: CommonProtocol> {
    var wrapper: Wrapper<T>
    ....
}

或者如果类型 T 对你来说实际上并不重要,那么:

func add(_ handler: @escaping (CommonProtocol) -> Void)

但第二个根本没有意义。每次使用此方法时都必须向下转换(向下转换非常糟糕:D)

注意:它实际上与此问题无关,但您的选择之一是也键入擦除 CommonProtocol

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-13
    相关资源
    最近更新 更多