Encountered an error in "Generic Where Clauses", still not able to figure out why! While it is same in the swift book

124 views Asked by At

Topic: Generic Where Clauses

protocol Container {
    
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}
struct Stack<Element>: Container {
    
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
 
    mutating func append(_ item: Element) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Element {
        return items[i]
    }
}
func allItemsMatch<C1: Container, C2: Container>
    (_ someContainer: C1, _ anotherContainer: C2) -> Bool
    where C1.Item == C2.Item, C1.Item: Equatable {
        if someContainer.count != anotherContainer.count {
            return false
        }
        for i in 0..<someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            }
        }
        return true
}
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
var arrayOfStrings = ["uno", "dos", "tres"]

Error comes here in if-else control flow

if allItemsMatch(stackOfStrings, arrayOfStrings) {
    print("All items match.")
} else {
    print("Not all items match.")
}

Error says that "arrayOfStrings" doesn't conform to the Container Protocol.

  • Tried many times but not able to figure out
  • Error exactly says - " Global function 'allItemsMatch' requires that '[String]' conform to 'Container' "
1

There are 1 answers

0
Leo Dabus On

As already mentioned in comments you forgot to declare that Array conforms to the Container protocol.

extension Array: Container { }

Not related to your question but you should also make your Stack structure conform to Sequence as well. It will allow you to use Sequence method elementsEqual

func elementsEqual<OtherSequence>(_ other: OtherSequence) -> Bool where OtherSequence : Sequence, Self.Element == OtherSequence.Element

So just add an index property to your Stack type and implement Sequence next property as follow:

struct Stack<Element>: Container {
    typealias Item = Element
    var items = [Item]()
    mutating func push(_ item: Item) { items.append(item) }
    mutating func pop() -> Item { items.removeLast() }
    mutating func append(_ item: Item) { push(item) }
    var count: Int { items.count }
    subscript(i: Int) -> Item { items[i] }
    var index: Int = 0
}

extension Stack: Sequence, IteratorProtocol {
    mutating func next() -> Item? {
        guard index < items.endIndex else { return nil }
        defer { index += 1}
        return items[index]
    }
}

Playground testing:

var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
var arrayOfStrings = ["uno", "dos", "tres"]
stackOfStrings.elementsEqual(arrayOfStrings)  // true