There is some subtlety in the examples. As a starting point, I suggest this article that walks through temporary scopes in various code patterns, including if let. It was written before edition 2024, but is still mostly accurate.
if let … = f(&String::from('🦀')) {
…
}
Once more, two options:
- The string is dropped after pattern matching, before the body of the
if let (that is, at the {). Or,
- The string is dropped after the body of the
if let (that is, at the }).
This time, there are reasons to go for option 2 rather than 1. It is quite common for a pattern in an if let statement or match arm to borrow something.
So, in this case, Rust went for option 2.
I.e. the temporaries from your iterator expression drop at the end of the if block.
And the rules are based on syntax, not types. Before the above snippet, the article notes
This sounds like we might want to go for a third option: make it depend on the signature of f.
However, Rust’s borrow checker only performs a check; it does not influence the behavior of the code.
Here the iterator temporary drops at the end of the let n statement.
And this is IMO the most subtle part. The iterator still drops at the end of the if let block with this variation. But the iterator type has a trivial destructor / the destructor is a no-op. The borrow checker recognizes that it cannot "observe" any borrows in its type. So going out of scope doesn't keep the borrow of x.0 alive.
With -> impl Iterator, however, the borrow checker assumes a more complicated destructor which can observe captured borrows. Indeed, it's intended to be a non-breaking change to replace the body of Foo::iter to return some custom iterator with such a destructor. So for that opaque type, going out of scope does keep the borrow of x alive.
Which suggests a fix: just return that concrete iterator type. Or, if you want to maintain the ability to change the function body without breaking consumers, wrap it in a new type.
Note, it'll now be a breaking change if you change the type to have a non-trivial destructor.