Rust gnubie. Some places don't allow a question that begins with "Why....". Hopefully this isn't one of those or, if so, someone can direct me to the proper forum. Thx in advance.
Why is there a difference between variable type declaration syntax (including function parameter type declaration syntax), function return type declaration syntax and type cast syntax?
Kindly ignore the silliness of the code -- I'm just trying to show examples of type declaration syntax.
fn main() {
let str1: String = String::from("[str1]"); // ": String" makes sense.
let str2: &String = &str1 ; // ": &String" makes sense
println!("str2={} ; myfn(str2)={}",str2,myfn(&str2.to_string()) );
}
fn myfn<'a>(s: &str) -> &str { // "s: &str". Same syntax. Cool.
// "-> &str" Huh whuh? Why not ":&str" ???
let i: i32 = s.parse::<i32>().unwrap() ;
let i2: i64 = i as i64; // why not just say "i:i64"
return s;
}
Note that let x = y as u32; and let x: u32 = y; do very different things, so it's a good thing that they're different syntax. (And conventions are moving away from as to named methods, which is why methods like cast exist on pointers.)
-> has been traditional for separating arguments and return types for a long, long time. Literally at least half a century, apparently: ML (programming language) - Wikipedia
("Why" is certainly allowed, so long as it's not code for "I think this is terrible and will insist that people agree it needs to be changed" )
If I read : Ty as "is a Ty", this would imply to me that myfn is a &str.
fn myfn(s: &str): &str /* = */ {
// ...
}
If I read it as "result type from callingmyfn"[1] I guess it works, but that's unintuitive to me; this is a declartion. Rust also has function pointers (and the Fn traits), so you may see
Rust uses both -> and => (the latter in match statements). That one did throw me and I still occasionally typo one or the other. (I believe the "why" is "parsing ambiguity" but couldn't find a citation.)
"type of the expression myfn(some_str_ref)" âŠī¸
This is to make the language easier to parse for humans, especially in the face of higher-order functions. fn foo<T>(f: fn(i32): i32, fn(T): U): U is not particularly easy to read.
Personally, the way i've always read : is as "of type" and -> as "to".
so for fn myfn(s: &str) -> &str reads exactly "myfn(s of type &str) to &str", definitely seems to work less well with trait and lifetime bounds though.