Why this fires
A collection method (each, for_each, forEach, filter, find, any,
all, len, take, skip, collect, to_array, contains) was called on a value that is
statically known to be a Result or Option wrapper. Those methods are
dispatched to Array/Iter/Map at runtime and are never valid on an
unwrapped wrapper.
use std::Database
let db = Database.open("sqlite://:memory:")?
db.query("SELECT * FROM users").each(|u| print(u.name))
// ^^^^ error[TE826]: `.each` does not exist on `Result<Rows, DbError>`;
// unwrap the Result first: `expr ?> .each(...)` (fallible pipe),
// `let v = expr?` then `v.each(...)`, or `.unwrap()`
The problem is that db.query(...) returns Result<Rows, DbError>. If you
call .each on it directly, the runtime's Array.* fallback iterates the
internal variant payload — the closure receives the whole rows array as one
argument, .name is nil, and the call returns nil, silently. No error is
ever raised; the wrong output just disappears.
The same applies to Option:
fn find_user(id: int) -> Option<User> { ... }
find_user(42).each(|u| print(u.name))
// ^^^^ error[TE826]: `.each` does not exist on `Option<User>`;
// unwrap the Option first with `.unwrap()`, `.unwrap_or(...)`,
// or match on Some/None before calling `.each(...)`
Fix it
1. Fallible pipe ?> (propagate Err/None)
Use the fallible pipe operator to unwrap the Ok/Some value and chain into
it, propagating any error up to the caller:
db.query("SELECT * FROM users") ?> .each(|u| print(u.name))
The function must declare a matching return type (Result<_, E> / Option<_>).
2. Bind then use
Unwrap with the ? postfix operator (propagates Err/None) and call the
method on the bound value:
let rows = db.query("SELECT * FROM users")?
rows.each(|u| print(u.name))
3. .unwrap() (panics on Err/None)
If you are certain the result is always Ok/Some and a panic on failure is
acceptable:
db.query("SELECT * FROM users").unwrap().each(|u| print(u.name))
Notes
- Methods that already dispatch correctly on
Result/Option—map,map_err,and_then,or_else,unwrap,unwrap_or,unwrap_err,is_ok,is_err— are not flagged by TE826. - The check is by type name, so a user-declared enum literally named
ResultorOptionalso trips this error. The prelude names are effectively reserved. - Even without static type information a runtime guard in the prelude dispatchers
catches the same mistake at runtime and emits a friendly message instead of
the cryptic
attempt to call method 39;each39; (a nil value). - See
docs/06-operators.mdfor the full?>/?/!.operator set.
See also
TE827—?.null-safe chaining used on aResult/Option.docs/06-operators.md—?>,?,!.fallible operators.docs/18-error-handling.md— Result/Option patterns.