Swift4中sequence(first:next:)函数语法错误排查咨询
I've run into this exact edge case before when implementing Collection for custom linked lists—let's break down what's happening here and fix it.
First, let's recap your scenario: you're following Ray Wenderlich's algorithms course to implement a LinkedList conforming to Collection. This implicit closure syntax works fine:
let nodes = sequence(first: lhs.node) { $0?.next }
But when you explicitly specify the closure's return type, you get an "Out of bounds: index >= endIndex" error:
let nodes = sequence(first: lhs.node, next: { aNode -> Node<Value>? in aNode?.next }) // Error here
What's Going Wrong
The issue isn't a syntax error—it's a type inference gotcha with Swift's sequence(first:next:) function. Let's look at the function's core signature to clarify:
func sequence<T>(first: T?, next: @escaping (T) -> T?) -> UnfoldSequence<T, T?>
When you omit the parameter type in your closure, Swift correctly infers T as Node<Value>, so:
first: lhs.nodeis treated asNode<Value>?(matching theT?parameter)- The closure receives a non-optional
Node<Value>($0) and returnsNode<Value>?(itsnextproperty)
But when you only specify the closure's return type (without the parameter type), Swift misinfers T as Node<Value>? instead. Now:
- The closure receives an optional
Node<Value>?(aNode) aNode?.nextreturnsNode<Value>?, which gets wrapped intoNode<Value>??to match the function's expectedT?return type- This causes the sequence to generate an extra
nilelement at the end, which clashes with yourCollectionimplementation (whereendIndexisnil, and accessingendIndexis invalid)
The Fix: Explicitly Specify the Parameter Type
To fix the error, you need to explicitly define the closure's parameter type as non-optional Node<Value>, which guides Swift to infer the correct T type for the sequence:
let nodes = sequence(first: lhs.node, next: { (aNode: Node<Value>) -> Node<Value>? in aNode.next })
You can even simplify it a bit—since the return type can now be inferred from aNode.next, you don't strictly need to specify it:
let nodes = sequence(first: lhs.node, next: { (aNode: Node<Value>) in aNode.next })
Why This Works
Now T is correctly inferred as Node<Value>, so:
- The sequence starts with
lhs.node(if it's non-nil) - For each element, the closure receives a non-optional
Node<Value>and returns itsnextproperty (an optional) - The sequence stops as soon as the closure returns
nil, so no extranilelements are added - This aligns perfectly with your
Collectionimplementation's index logic (whereendIndexisnil, and we never try to access it)
内容的提问来源于stack exchange,提问作者black_pearl

