为什么Swift编译器在返回不透明类型以符合`Sequence`协议时无法推断泛型类型

zd287kbt  于 2023-04-04  发布在  Swift
关注(0)|答案(2)|浏览(117)

我有一个Swift包,里面有一个LinkedList类的实现。我想让我的LinkedList符合Sequence协议。为此,makeIterator返回LinkedListIterator示例,它隐藏在不透明的IteratorProtocol类型后面,如下所示:

extension LinkedList: Sequence {
    public func makeIterator() -> some IteratorProtocol {
        LinkedListIterator(head: head)
    }
}

对于上面的opaque类型,当我想使用序列特性(如map)时,我会出现编译错误:

func test_list_has_expected_elements() {
    let list = LinkedList(2, 4, 2, 3)
    XCTAssertEqual(list.map{ $0 }, [2, 4, 2, 3]) //Cannot convert value of type 'Int' to expected element type 'Array<(some IteratorProtocol).Element>.ArrayLiteralElement' (aka '(some IteratorProtocol).Element')
}

在将Sequence一致性从opaque类型更改为LinkedListIterator<T>之后,它编译时没有错误,但是它将LinkedListIterator实现强制为public,这是不希望的。

extension LinkedList: Sequence {
    public func makeIterator() -> LinkedListIterator<T> {
        LinkedListIterator(head: head)
    }
}

如何将实现改为opaque类型,并提供Sequence API?

以下是我的LinkedList的完整实现:

public class LinkedList<T> {
    
    var head: Node<T>?
    
    init(_ elements : T...) {
        if let first = elements.first {
            var last = Node(data: first)
            head = last
            elements.dropFirst(1).forEach { element in
                let next = Node(data: element)
                last.next = next
                last = next
            }
        }
    }
    
    public func append(data: T) {
        let newNode = Node(data: data)
        if let last {
            last.next = newNode
        } else {
            head = newNode
        }
    }
    
    public var count: UInt {
        var runner = head
        var count: UInt = 0
        while let node = runner {
            count += 1
            runner = node.next
        }
        return count
    }
    
    private var last: Node<T>? {
        if var runner = head {
            while let next = runner.next {
                runner = next
            }
            return runner
        }
        return nil
    }
}

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension LinkedList: Sequence {
    /*
    public func makeIterator() -> LinkedListIterator<T> {
        LinkedListIterator(head: head)
    }
    */
    
    public func makeIterator() -> some IteratorProtocol {
        LinkedListIterator(head: head)
    }
}

public struct LinkedListIterator<T>: IteratorProtocol {
    
    private var currentNode: Node<T>?
    
    init(head: Node<T>? = nil) {
        self.currentNode = head
    }
    
    public mutating func next() -> T? {
        if let node = currentNode {
            currentNode = node.next
            return node.data
        } else {
            return nil
        }
    }
}

Swift详细信息:swift-driver版本:1.62.15 Apple Swift版本5.7.1(swiftlang-5.7.1.135.3clang-1400.0.29.51)

mwkjh3gx

mwkjh3gx1#

你甚至会得到错误:

XCTAssertEqual(list.map{ $0 }, list.map{ $0 })

这是opaque类型的问题,你对它的associatedtype类型一无所知。所以如果可以的话,最好返回确切的类型。当结果中有可怕的泛型时,只需要不透明的类型。

k97glaaz

k97glaaz2#

你只需要做一个小小的调整,它就会工作:

extension LinkedList: Sequence {
    public func makeIterator() -> some IteratorProtocol<T> {
        LinkedListIterator(head: head)
    }
}

如果没有在T上专门化IteratorProtocol,编译器将认为它的Element是Any(即具有任何元素类型的不透明迭代器类型)。

相关问题