要求关联类型在 @convention(c) 块中可表示



我想有一种通用的方式来做一些事情,就像在 Swift 3 中一样:

public protocol Callable {
    associatedtype In : CVarArg
    associatedtype Out : CVarArg
}
public struct IntCallable : Callable {
    public typealias In = Int
    public typealias Out = Double
    public typealias FunctionalBlock = @convention(c) (In) -> Out
    public func call(_ block: FunctionalBlock) { /* do stuff */ }
}

所以我希望它看起来更像这样:

public protocol Callable {
    associatedtype In : CVarArg
    associatedtype Out : CVarArg
    typealias FunctionalBlock = @convention(c) (In) -> Out
}
public struct IntCallable : Callable {
    public typealias In = Int
    public typealias Out = Double
}
public extension Callable {
    public func call(_ block: FunctionalBlock) { /* do stuff */ }
}

但是,我收到错误:

'(Self.In) -> Self.Out' is not representable in Objective-C, so it cannot be used with '@convention(c)'

我可以对 In/Out 关联类型施加任何约束,以允许我声明功能块的泛型形式?它在没有@convention(c)的情况下工作正常,但我需要它来形成 C 函数调用。

这在 Swift 中目前是不可能的,因为 Swift 管理作为协议传递的值的方式,而CVarArg是一个协议。

幕后发生的事情是,当在协议的保护伞下传递值时,Swift 编译器会创建一个包装值的存在容器,该值在被调用方站点透明地解包。

所以基本上你的块实际上看起来像这样:

typealias FunctionalBlock = @convention(c) (Container<In>) -> Container<Out>

由于这种幕后转换,您不会传递可以用 C 表示的值,因此会出现错误。

这与其他协议相关问题非常相似,例如著名的协议不符合自身?

最好的办法是为符合 CVarArg 的所有类型添加重载,因为这是一个有限且不可更改的列表。

最新更新