How much syntax sugar has Rust?


Rust is a low-level programming language, so I wonder what these beautiful abstractions transform to.

I’ve a few idea about how could this be like, e.g. a for loop going to be an if and goto etc. How about the other ones?


A few quick things I can recall just right now (in pairs of sugared and desugared things):

fn func<F>() where F: Fn(u32) -> u64 {} // is the same as:
fn func<F>() where F: Fn<(u32,), Output=u64> {}
let a = [1u32, 2, 3, 4];

let b = &a[..];
let c = &a[1..];
let d = &a[..3];
let e = &a[1..3];

// are the same as:

let b = &a[RangeFull];
let c = &a[RangeFrom {start: 1}];
let d = &a[RangeTo {end: 1}];
let e = &a[Range {start: 1, end: 3}];


Is ‘end: 1’ right?


See yourself:


Closures are entirely sugar.


And indexing is also desugars further:

// from: 
let x = &a[1..3];
// to:
let x = &a.index(Range { start: 1, end: 3 });


Then if let and while let can be viewed as a sugar for match { ... } and loop { match { ... } }.


I wonder if match is a sugar.


No, you can’t do pattern matching without match, it’s a basic language feature.


Many binary operations are implemented with traits (see Add, Sub, Div, Mul for example), so you also think of them as a syntax sugar, although I’m not sure if it’s a real sugar or just an implementations detail of operator overloading.


Deref coercion is some nice sugar.

let s: String = "hi".to_string();
let t: &str = &s;

And traits as used for example with Into<Cow<'a, str>> and AsRef<Path> provide very sugary interfaces without extra language features:

File::open("file.txt");  // fn open<P: AsRef<Path>>(path: P)


I’m not sure trait bounds usage can be qualified as a sugar, as it’s more a type system feature.


Also dynamic dispatch with trait objects can be thought as a sugar, as it creates virtual method tables and “fat pointers” behind the scene.


In the end, everything is syntax sugar for some sequence of literal bytes; I mean, where do you draw the line?


without extra explanation, newbie will be get confused.

Things like,

I still can not understand

File::open("file.txt");  // fn open<P: AsRef<Path>>(path: P)

“file.txt” is &str.

but no AsRef impl for it

impl AsRef<Path> for Path
impl AsRef<Path> for OsStr
impl AsRef<Path> for OsString
impl AsRef<Path> for str
impl AsRef<Path> for String
impl AsRef<Path> for PathBuf

can anyone give me some explanation? thanks.


It is actually, but in two steps. You have the impl AsRef<Path> for str implementation for str and impl<'a, T, U> AsRef<U> for &'a T where U: ?Sized, T: AsRef<U> + ?Sized which makes every reference to T implement AsRef<U> if T: AsRef<U>. This makes &str implement AsRef<Path> because str implements it.


I did make a small example of &String turning into &str by itself (by “coercion”)


I mean Deref coercion confuse newbie in general, not meaning your example is confusing. I understand it only after the nightly doc comes out. Thanks for your example.


Thanks. that makes me feel better. I feel bad when I can not reason something.


That’s good. Ask questions :smile: