简体   繁体   English

Swift中条件一致性的解决方法(是:将协议添加到受约束的泛型类型中)

[英]Workaround for conditional conformance in Swift (was: Adding protocol to a constrained generic types)

The code snippet below demonstrates the problem I am trying to solve. 下面的代码段演示了我要解决的问题。

import Foundation

protocol Printable {
    func className() -> String
}

class SomeType: Printable {
    func className() -> String {
        return "SomeType"
    }
}

class List<T> {
}

extension List where T: SomeType {
    func className() -> String {
        return "List<SomeType>"
    }
}

func test(type: Any, message: String) {
    guard type is Printable else {
        print("\(message): ERROR")
        return
    }
    print("\(message): SUCCESS")
}

let s: Any = SomeType()
test(type: s, message: "#1")

let slist1: Any = List<Any>()
test(type: slist1, message: "#2")

let slist2: Any = List<SomeType>()
test(type: slist2, message: "#3")

How can I get this: 我怎么能得到这个:

> #1: SUCCESS  <--- as expected
> #2: ERROR    <--- it's okay
> #3: SUCCESS  <--- I am getting ERROR instead

It seems that adding a protocol to this line would do the trick: 似乎向该行添加协议可以解决问题:

extension List: Printable where T: SomeType { // COMPILE ERROR

But unfortunately, this is not allowed. 但不幸的是,这是不允许的。

Another way to do it could be to use: 另一种方法是使用:

extension List where T: Printable { // COMPILES OK in Swift 2.3 but doesn't work. COMPILE ERROR in Swift 3.0

But again, no luck passing the test. 但是同样,没有运气通过测试。

What else can I do to add a protocol to a constrained generic type? 我还可以做些什么来将协议添加到受约束的泛型类型?

Okay so in your guard you're asking "if this is Printable then print success else print Error" and with your first example you have s which is SomeType which is printable. 好吧,在您的警惕下,您要问“如果这是可打印的,那么打印成功,否则打印错误”,在第一个示例中,您有s,它是可以打印的SomeType。 That's fine. 没关系。

After that you have slist1 which is type List<Any> which is definitely not of type printable and you get "Error". 之后,您将拥有类型为List<Any> slist1,该List<Any>绝对不是可打印的类型,并且会出现“错误”。 That's fine 没关系

Next you have List<SomeType> . 接下来,您有了List<SomeType> Now you have a class extension that defines T to be SomeType, correct? 现在您有了一个类扩展,将T定义为SomeType,对吗? But you're only defining T to be SomeType and not the actual List so when you pass the entire List into the test function you're not going to get your test to pass because List<AnyTypeHere> is not Printable because the list itself doesn't implement Printable. 但是您只是将T定义为SomeType而不是实际的List,因此当您将整个List传递给测试函数时,您将无法通过测试,因为List<AnyTypeHere>无法打印,因为列表本身没有没有实现Printable。

Now the question is, do you want the entire list to be printable? 现在的问题是,您是否希望整个列表都可打印? If so, then just make it conform to the SomeType or Printable protocol. 如果是这样,则只需使其符合SomeType或Printable协议即可。 That's the only way you'll get that to pass other than you passing individual List<SomeType> elements into the function. 除了将单个List<SomeType>元素传递到函数中之外,这是传递它的唯一方法。 Your function logic is correct but it's just a misuse of the concept. 您的函数逻辑是正确的,但这只是对该概念的滥用。

So if you want the List<SomeType> to make that pass then you could do something like 因此,如果您希望List<SomeType>通过该传递,则可以执行类似的操作

class List<T> : Printable where T:SomeType {
  //Add code here that conforms to protocol
}

Doing that will make your second test fail because Any doesn't inherit from SomeType but it'll make your third test pass because now List<T> is Printable and T is also of type SomeType. 这样做将使您的第二次测试失败,因为Any不会从SomeType继承,但是它将使您的第三次测试通过,因为现在List<T>是Printable且T的类型也是SomeType。 I mean, that's just a real quick way to get what it looked like you wanted to begin with. 我的意思是,这只是一种获取所需外观的快速方法。 You're not going to have the second and third tests pass at the same time unless you add something extra because the second test is List being of type Any while the third is List being of type Printable. 除非您添加其他内容,否则您将不会同时通过第二个和第三个测试,因为第二个测试是List的类型为Any,而第三个测试的List的类型为Printable。 So either one of them will throw an error (because List isn't of type Printable) or all tests show success (because List is of type Printable) 因此,其中之一将引发错误(因为List的类型不是Printable)或所有测试都显示成功(因为List的类型是Printable)

An updated answer now that we have Swift 4.2, conditional conformance is now added as a feature. 现在有了Swift 4.2,这是一个更新的答案,现在将条件一致性添加为功能。

From their spec on Github , this sort of code is now valid 从他们在Github上规范来看,这种代码现在有效

   extension List : Printable where T: SomeType {
       func className() -> String {
           return "List<SomeType>"
       }
   }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM