Issue
I am learning how to connect database to Rust program. There something I don't quite understand:
PgConnection::establish(&database_url).unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
What does this expression mean? What does |_|
mean?
Solution
Ignoring the underscore _
for now, Rust uses pipes |
to delimit the parameter-list of a closure (aka lambda-function, anonymous function, etc). For comparison, JavaScript and C# use normal parentheses and a fat arrow ( ) =>
to denote their closures (a closure is just an anonymous function with environment capture semantics), like so:
// JavaScript:
const smallerArray = bigArray.filter( ( x, idx ) => idx < 5 );
// C#:
T[] smallerArray = bigArray.Where( ( T item, Int32 idx ) => idx < 5 ).ToArray();
Instead of being a conformist and using ( ) =>
like everyone else, Rust opts for a different syntax for the parameter-list: it uses |a, b, c|
for single-line functions and |a, b, c| { stuff }
for multi-line functions, and without any arrow symbology.
...so the above JavaScript and C# would be translated into Rust like so:
let smaller_array = big_array.into_iter().filter( |item| item < 5 )
As for the underscore: Rust shares C#'s convention for using an underscore to denote a discarded or otherwise ignored parameter or local. Now you might wonder what the point of a discarded parameter is: why not just omit it entirely like in JavaScript? (e.g. bigArray.filter( x => x < 5 )
and bigArray.filter( ( x, idx ) => x < 5 )
and bigArray.filter( ( x, idx, arr ) => x < 5 )
are all equivalent.
...well, JavaScript doesn't support function overloading: each function name resolves to a single function implementation, so omitting unused parameters isn't a problem. Now while Rust doesn't support function overloading either, it's still a very large and complex language that has many situations where you will need to explicitly declare a parameter that you don't use (strictly speaking, _
represents an unbound identifier and you cannot use _
as a variable).
The main use-case for naming a function parameter to _
in Rust is because it's a value annotated with the "must_use
" attribute - but if you really know you don't need to use that (bound) parameter and you don't want to be bombarded with low-value compiler warnings about must_use
values, then _
is a handy solution.
Another use-cases of _
is to declare that a call-site's return-value is being willfully discarded (so this syntax signifies intent), for example:
let _ = someFunctionThatReturnsAValue();
...whereas if you simply put someFunctionThatReturnsAValue();
on its own line then anyone else reading the code, or a static-analysis tool, will think you absent-mindedly forgot to check someFunctionThatReturnsAValue
's return-value - but using let _ = ...
makes it clear that you really don't care about the return value such that you don't want static-analysis tools dinging you.
So given unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
, what does |_|
mean?
unwrap_or_else
is a method ofstd::result
.unwrap_or_else
's parameter is a callback functionop: FnOnce
. If theresult
is-not-Ok
thenop
will be invoked andop
's return-value becomes the end-result of theunwrap_or_else
expression (or it panics... your call).- Crucially, the
op
function inunwrap_or_else
accepts one (1) parameter which is theE
error-value contained within theresult
. - In this case, the
panic!("Error connecting to {}", database_url))
expression doesn't use the inner error value at all (which I think is a bad idea) so the callback closure/function discards the value by using the_
syntax.
- Crucially, the
So in conclusion,
|_|
inunwrap_or_else(|_| panic!("Error")
means "The argument ofunwrap_or_else
is an anonymous function accepting anE
(error value)-typed parameter - buuuut we just don't care about it, so pretend it doesn't exist".
Answered By - Dai Answer Checked By - Marilyn (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.