繁体   English   中英

与泛型类型和协议关联的类型约束允许绕过 WHERE 子句

[英]Associated type constraints with generic types and protocols enables bypass of the WHERE clause

为了完全理解问题,我在代码中评论了我的想法。 为了便于查看,您可以将粘贴复制到 SWIFT 操场上。 不确定这是错误还是对类型推断的根本误解。 我能够通过“欺骗”类型推断来绕过 WHERE 子句,让我发送不同的类型。

    import Foundation

protocol Container {
  associatedtype Item
  mutating func append(_ item: Item)
  var count: Int { get }
  subscript(i: Int) -> Item { get }
}

struct Stack<U>: Container {
  var items = [U]()
  mutating func push(_ item: U) {
    items.append(item)
  }
  mutating func pop() -> U {
    return items.removeLast()
  }
  // conformance to the Container protocol
  mutating func append(_ item: U) {
    self.push(item)
  }
  var count: Int {
    return items.count
  }
  subscript(i: Int) -> U {
    return items[i]
  }
}

struct Devin {} /// This is to describe a custom type.

extension Devin: Container {
  //typealias Item = String

  /// NOTE: Eventhough the typealias is omitted, the type is inferred as String due to the pattern defined here.
  mutating func append(_ item: String) {
    /// do nothing
  }
  var count: Int {
    /// do nothing
    return 0
  }
  subscript(i: Int) -> String {
    /// do nothing
    return "0"
  }
}

/// and here comes the confusing part.......

// Using a PROTOCOL in its ASSOCIATED TYPE'S constraints

protocol SuffixableContainer: Container {
    /// Here we are saying SUFFIX like the ITEM constraint before is a type that conforms to this protocol being defined and the actual constraint is the where clause.
  associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
    /// Suffix has two constraints: It must conform to the SuffixableContainer protocol (the protocol currently being defined)
    /// and its Item type must be the same as the container’s Item type. ( what does it look like when they arent the same? )
    /// to understand whats happening here you have to see how its being used.
    ///
                               /// here is where its getting used and this is the important piece
    func suffix(_ size: Int) -> Suffix
}

extension Stack: SuffixableContainer {
                                /// when conforming
    func suffix(_ size: Int) -> Stack {
        var result = Stack()
        for index in (count-size)..<count {
            result.append(self[index])
        }
        return result
    }
    // Inferred that Suffix is Stack.
}

/// in the commented out code below:
/// Eventhough, returning a stack in the generic form passed, returning one of a different type than the STRING that was inferred will throw an error.
/// Here we can return an instance of Devin and be fine but when we return an instance of a Stack that is a INT type it errors.
//extension Devin: SuffixableContainer {
//  func suffix(_ size: Int) -> Stack<Int> {
//    return Stack<Int>()
//  }
//}
/// Error:  note: requirement specified as 'Self.Item' == 'Self.Suffix.Item' [with Self = Devin]
/// This is the behavior you would expect

/// But here is a different story
/// Return (  Stack = just fine | Devin = just fine | Stack<Devin> = no go my friend )
extension Devin: SuffixableContainer {
  func suffix(_ size: Int) -> Devin {
    print(size)
    return Devin()
  }
}

print(Devin.Suffix.self)
print(Devin.Item.self)
if Devin.Item.self == Devin.Suffix.self {
  print("It Worked")
} else {
  print("They arent the same")
  /// For those who can guess it will print that they aren't the same which violates the where clause
}
let store = Devin.suffix(Devin())
/// Not sure I understand why this works


/// now here is where I can really see the issue.
/// After printing the two types Devin does not equal String &
/// Devin and String are not the same types and the where clause didnt throw any error.
/// And for whatever reason I can pass the Devin object

where子句不限制Devin.SuffixDevin.Item相同,它限制Devin.Suffix.ItemDevin.Item相同。

保持其他一切不变,以下代码打印It Worked

print(Devin.Suffix.Item.self)
print(Devin.Item.self)
if Devin.Item.self == Devin.Suffix.Item.self {
  print("It Worked")
} else {
  print("They aren't the same")
}

暂无
暂无

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

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