代码之家  ›  专栏  ›  技术社区  ›  Lorenzo B

使用闭包时无法显式专门化泛型函数

  •  2
  • Lorenzo B  · 技术社区  · 7 年前

    我有这样一个函数:

    func register<T: Routable>(_ action: Action, withCallback callback: @escaping (T?) -> Void) {
        notificationCenter.addObserver(forName: actionMap[action], object: nil, queue: .main, using: { notification in
        let routable = T(userInfo: notification.userInfo)
            callback(routable)
        })
    }
    

    在哪里? Routable 定义如下:

    protocol Routable {
        init?(userInfo: [AnyHashable: Any]?)
    }
    

    当我尝试使用它时,我收到

    无法显式指定泛型函数

    这是用法:

    controller.register<Navigate>(Action.navigate) { [unowned self] navigate in
        // do something
    }
    

    有什么办法让编译器高兴吗?

    2 回复  |  直到 7 年前
        1
  •  3
  •   Rob Napier    7 年前

    我认为这纯粹是一个语法问题。不能像这样直接传递类型参数。你需要改为“填空”。为此,需要将类型添加到 navigate 以下内容:

    controller.register(Action.navigate) { [unowned self] (navigate: Navigate?) in ... }
    

    有时这种语法很烦人,因为它隐藏了类型。你可以通过重写 register 这种方式:

    func register<T: Routable>(action: Action, returning: T.type,
                               withCallback callback: @escaping (T?) -> Void)
    

    你可以这样称呼它:

    controller.register(action: .navigate, returning: Navigate.self) { 
        [unowned self] navigate in 
        // ...
    }
    

    这个 returning 参数未直接用于函数中。它只是提供了一种更明确的方法来专门化函数。

        2
  •  0
  •   Scott Thompson    7 年前

    很难说没有看到更完整的代码示例…但基本上编译器告诉你的是“你告诉我你希望register函数是泛型的(因为它有一个类型参数),但是你也试图告诉我到底要使用什么类型,我不喜欢”。

    在调用中添加特定类型参数时,将“显式专门化”函数:

    controller.register<Navigate>...
    # Right Here       ^^^^^^^^^^
    

    编译器希望灵活地确定调用什么样的寄存器函数。我想你想要的是:

    controller.register(Action.navigate) {...
    

    如果您没有显式地专门化泛型函数,而是让编译器找出要使用的专门化。