【问题标题】:Generic completion passed as non-generic泛型完成作为非泛型传递
【发布时间】:2017-08-21 19:54:43
【问题描述】:

我正在开发一些框架并遇到了问题。

我有一个公共协议:

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) -> () 完成部分“转换”为 (MyPublicProtocol1) -> ()? p>

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

【问题讨论】:

  • 我建议您更清楚地了解您打算使用的用途以及您尝试通过尝试的解决方案解决的潜在问题。经常发现最好的解决方案与我目前的方法不同。

标签: swift generics swift3 protocols


【解决方案1】:

你要求的东西不能证明是真的。你有一个方法:

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

这接受一个可以接收 any 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) -> ())
}

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

【讨论】:

    【解决方案2】:

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

    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)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-05
      • 2014-04-13
      • 1970-01-01
      • 1970-01-01
      • 2016-02-12
      • 2019-02-27
      相关资源
      最近更新 更多