You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift返回不透明类型遵循Sequence协议,如何解决泛型推断问题?

如何让Swift的LinkedList用不透明类型实现Sequence协议且正常使用API?

问题场景

我有一个Swift包实现了LinkedList类,想要让它遵循Sequence协议。最初用不透明类型返回迭代器的实现如下:

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

但调用map等Sequence特性时会触发编译错误:

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

如果改成返回具体的LinkedListIterator<T>类型,代码能正常编译,但必须将LinkedListIterator设为public,这不符合隐藏内部实现的需求:

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

完整代码参考

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 version: 1.62.15 Apple Swift version 5.7.1 (swiftlang-5.7.1.135.3 clang-1400.0.29.51)

解决方案

问题根源是Swift无法自动推断出不透明类型some IteratorProtocol的关联类型Element为T,需要显式约束关联类型,同时隐藏迭代器的具体实现:

  1. 修改makeIterator的返回类型,显式指定关联类型Element = T:
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension LinkedList: Sequence {
    public func makeIterator() -> some IteratorProtocol<Element = T> {
        LinkedListIterator(head: head)
    }
}
  1. 将LinkedListIterator的访问级别改为默认的internal(去掉public修饰符),隐藏内部实现:
struct LinkedListIterator<T>: IteratorProtocol {
    
    private var currentNode: Node<T>?
    
    init(head: Node<T>? = nil) {
        self.currentNode = head
    }
    
    mutating func next() -> T? {
        if let node = currentNode {
            currentNode = node.next
            return node.data
        } else {
            return nil
        }
    }
}

这样修改后,既通过不透明类型隐藏了迭代器的具体实现,又能让Swift正确推断Sequence的元素类型,正常使用map、filter等所有Sequence API。

内容的提问来源于stack exchange,提问作者rojarand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 07:32:21