I disagree that it would be without sacrifice. That's kind of the whole point.
Unless I'm missing something, go has iterators with for loops.
Go's for loops can only iterate over builtin types: slices, maps, channels, etc. You can't produce a custom type that is to be iterated over.
The zero of Error is nil, so logically this would be Result(0, nil). But what do you set the internal state? It's not Ok, cause that int isn't used, and it's not Err either.
Option would work fine though and it would be amazing to map over options instead of nil checks.
I think you'd need to build Result on top of Option, it's naturally kind of ternary - "I have value" "I have error" "idk", either internally or externally.
What might be awesome would be if the Error were a slice type, nil would be "uninitialized" and empty slice means "initialized". still not...pleasant.
[0]: https://doc.rust-lang.org/std/default/trait.Default.html
Since it's implemented for Option<T> you can do it the same way [3] for that, but that's not available for Result<T,U> since the semantics are different from Option which is basically just Rust's alternative for 'null'/'nil' (but verifiable by the compiler).
Thus you'd have to choose what variant of the enum you want to have at initialization, after which you can use the Default implementation of the enclosed type, if available (and so on, if there are more nested types).
Though honestly I can't recall using the kind of pattern in Rust that would "need" something like that. Through the handling of code blocks as expressions, early returns etc. you for example don't need to initialize a variable before having an if-/match-/for-/while-/etc. block, you can simply use that block as an expression on the right side of the assignment [4].
[0]: https://play.rust-lang.org/?version=stable&mode=debug&editio...
[1]: https://doc.rust-lang.org/stable/error-index.html#E0381
[2]: https://play.rust-lang.org/?version=stable&mode=debug&editio...
[3]: https://play.rust-lang.org/?version=stable&mode=debug&editio...
[4]: https://play.rust-lang.org/?version=stable&mode=debug&editio...
It would also allow defer-like syntax to be used on the value a function returns, to return early from the calling function. Rust's ? is an excellent example of this, allowing explicit delegation of error handling that is still very lightweight syntactically.
Foo, err requires either that all receiving functions accept (foo, err), or manually nil-checking at every stage.
Try/catch is the least composable, because deeper error types can "jump out" from any layer. Which means you have to keep wrapping catches, until you hit some base layer you can recover from. You get stack traces, but you lose type information along the way.
Sum (result) and product (foo, nil) types preserve type information. Meaning you can operate more generically over it. Meaning less code duplication.