通用完成作为非泛型传递

时间:2017-08-21 19:54:44

标签: swift generics swift3 protocols

我正在研究一些框架并面临一个问题。

我有一个公共协议:

public protocol MyPublicProtocol1 {
}

另一个,它包含一个传递了泛型参数的函数。通用参数有一个约束 - 参数类型必须实现第一个公共协议:

public protocol MyPublicProtocol2 {
    func someFunc<T: MyPublicProtocol1>(completion: (T) -> ())
}

然后我在公共课程中实现我的协议。在具有泛型参数的函数内部,我必须调用另一个不带泛型参数的函数,看起来像这样:

func anotherFuncWith(completion: (MyPublicProtocol1) -> ())

这是实现的样子:

class MyPublicProtocol1Impl: MyPublicProtocol1 {
}

class MyPublicProtocol2Impl: MyPublicProtocol2 {
    func someFunc<T: MyPublicProtocol1>(completion: (T) -> ()) {
        anotherFuncWith(completion: completion)
    }
}

当然我在最后一个字符串中有错误。

我不能声明 someFunc(completion :) 而不是通用参数,如:

func someFunc(completion: (MyPublicProtocol1Impl) -> ())

因为 MyPublicProtocol1Impl 类不能公开。而且由于某些原因,我也无法声明 anotherFuncWith(completion :) 来获取泛型参数。

有没有办法在某种程度上“转换”(T:MyPublicProtocol1) - &gt; ()完成只是(MyPublicProtocol1) - &gt; ()

非常感谢任何帮助或建议!谢谢你阅读我的故事!

2 个答案:

答案 0 :(得分:0)

你已经要求了一些不可证实的事情。你有一个方法:

func anotherFuncWith(completion: (MyPublicProtocol1) -> ())

这接受一个可以接收任何 MyPublicProtocol1的方法。然后,您传递一个类型的方法:

(T: MyPublicProtocol1) -> ()

anotherFuncWith可能会传递不是T的内容,此时这是未定义的。为了使它更具体,让我们摆脱这里的大部分内容,让MyPublicProtocol1成为Any(只是为了选择一个简单的协议)。

func anotherFuncWith(completion: (Any) -> ()) {
    completion("This is a string which is an Any, so that's fine")
}

func someFunc<T: Any>(completion: (T) -> ()) {
    anotherFuncWith(completion: completion)
}

这无法完全像您的示例一样进行编译。现在让我们思考如果编译我能做什么。我可以打电话:

func complete(x: Int) -> () {
    print(x + 1)
}

someFunc(completion: complete)

所以现在anotherFuncWith调用complete传递String,无法添加。崩溃。

这里的根本问题是你已经倒退了covariance and contravariance

我们如何解决?取决于你的意思。这段代码有点奇怪。您是否关心T的实际类型?你似乎永远不会使用它。如果您不在乎,那么只需使用协议:

public protocol MyPublicProtocol2 {
    func someFunc(completion: (MyPublicProtocol1) -> ())
}

如果您关心实际类型,请使用PAT:

public protocol MyPublicProtocol2 {
    associatedtype T: MyPublicProtocol1
    func someFunc(completion: (T) -> ())
}

或者你可能想重新考虑一下你是否需要一个协议。我经常发现人们在不需要协议的时候会找到它们。你有这些协议的多个实现吗?你有多种类型的传递?如果没有,我会简化并且只有在您遇到当前代码中遇到的实际问题时才会使用通用/协议。 (你可能需要它们;这只是我的股票建议,许多人在他们过度设计时发现它们很有用。)

答案 1 :(得分:0)

解决这个问题的肮脏方式是

func someFunc<T: MyPublicProtocol1>(completion: (T) -> ()) {
    anotherFuncWith { (thing) in
        if let tThing = thing as? T {
            completion(tThing)
        }
    }
}

如果你非常确定围绕它的代码,我只会这样做,因为它肯定是错误的。

此外,这也有效。我不确定你真正想要做什么,所以我不确定它是否能解决你的问题

func anotherFuncWith<T: MyPublicProtocol1>(completion: (T) -> ()) {

}

class MyPublicProtocol2Impl: MyPublicProtocol2 {

     func someFunc<T: MyPublicProtocol1>(completion: (T) -> ()) {
         anotherFuncWith(completion: completion)
    }
}