# supertrait bound

That : Iterator is a supertrait bound.It reads: "to implement IteratorExt for a type, that type must already implement Iterator."Iterator is the supertrait; IteratorExt is the subtrait. It is not inheritance in the OOP sense — IteratorExt doesn’t “extend” or contain Iterator’s methods.It’s a requirement/constraint. It’s essentially shorthand for a where clause on the trait itself: pub trait IteratorExt: Iterator { ... }
means the same as pub trait IteratorExt where Self: Iterator { ... }
It buys you two concrete things:

  1. Inside the trait, you can use the supertrait’s methods.
    Because the compiler now knows any Self is also an Iterator, my second method was allowed to call self.next() — next comes from Iterator, not from IteratorExt:
    I also wrote Self::Item freely — that associated type comes from Iterator too.
    Drop the : Iterator, and both self.next() and Self::Item stop compiling, because nothing guarantees Self has them.
  2. Anyone who implements IteratorExt is forced to also implement Iterator.
    You can’t opt into the sub-trait while skipping the super-trait:

When you use a trait, you need import the trait to scope.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
mod ext {
pub trait IteratorExt: Iterator {
fn second(mut self) -> Option<Self::Item>
where
Self: Sized,
{
self.next();
self.next()
}
}

impl<I: Iterator> IteratorExt for I {}

// struct Foo;
// impl IteratorExt for Foo {} // ERROR: the trait bound `Foo: Iterator` is not satisfied
}

fn main() {
let v = [10, 20, 30];

// ERROR: no method named `second` found for struct `Iter` ...
// the trait `ext::IteratorExt` defines an item `second`,
// perhaps you need to `use ext::IteratorExt;`
use ext::IteratorExt;
let x = v.iter().second();
println!("{:?}", x);
}

# What is the syntax: method::<SomeThing>() ?

This construct is called turbofish(tuna fish). If you search for this statement, you will discover its definition and its usage.

path::<…>, method::<…> Specifies parameters to generic type, function, or method in an expression; often referred to as turbofish (e.g., “42”.parse::<i32>())

You can use it in any kind of situation where the compiler is not able to deduce the type parameter, e.g.

1
2
3
4
5
fn main () {
let a = (0..255).sum();
let b = (0..255).sum::<u32>();
let c: u32 = (0..255).sum();
}

a does not work because it cannot deduce the variable type.
b does work because we specify the type parameter directly with the turbofish syntax.
c does work because we specify the type of c directly.

let p: SomeThing = method(); just a grammar sugar for let p = method::<SomeThing>();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
fn main() {
// Rust uses the turbofish (::<T>) to specify generic type parameters.
let p = make::<Point>();
println!("{:?}", p);
// inferred as make::<Point>()
let p: Point = make();
println!("{:?}", p);
// Rust does not use the angle‑bracket syntax after the function name like some languages.
// let p = make<Point>();

// Why Rust uses ::<Point> instead of <Point>
// because < could mean:
// 1. a generic type parameter
// 2. a "less than" operator
// 3. the start of a comparison expression
// To avoid ambiguity, Rust requires the turbofish:
}

#[derive(Debug, Default)]
struct Point {
x: i32,
y: i32,
}

fn make<T: Default>() -> T {
T::default()
}

# Why the size for values of type [u8] cannot be known at compilation time?

1
2
3
4
5
6
7
// @ the size for values of type `[u8]` cannot be known at compilation time, the trait `std::marker::Sized` is not implemented for `[u8]`
// const CHARSET: [u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
// abcdefghijklmnopqrstuvwxyz\
// 0123456789)(*&^%$#@!~";
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789)(*&^%$#@!~";

# How to open file with open and write mode ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// File::open open file only read mode, so write content will PermissionDenied
// let mut f = std::fs::File::open("foo.txt")
// .ok()
// .expect("Couldn’t open foo.txt");
// let buf = b"hello";
// f.write(buf).expect("Couldn’t write to foo.txt"); // thread 'main' panicked at 'Couldn’t write to foo.txt: Os { code: 5, kind: PermissionDenied, message: "拒绝访问。" }'

let mut f = std::fs::OpenOptions::new()
.read(true)
.write(true)
.open("foo.txt")
.ok()
.expect("Couldn’t open foo.txt");

let buf = b"hello";
f.write(buf).expect("Couldn’t write to foo.txt");

# What mean of ref & ref mut below?

1
2
3
4
5
let mut x = 5;

match x {
ref mut mr => println!("mut ref {}", mr),
}

When doing pattern matching or destructuring via the let binding, the ref keyword can be used to take references to the fields of a struct/tuple. The example below shows a few instances where this can be useful:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#[derive(Clone, Copy)]
struct Point { x: i32, y: i32 }

fn main() {
let c = 'Q';

// A `ref` borrow on the left side of an assignment is equivalent to
// an `&` borrow on the right side.
let ref ref_c1 = c;
let ref_c2 = &c;

println!("ref_c1 equals ref_c2: {}", *ref_c1 == *ref_c2);

let point = Point { x: 0, y: 0 };

// `ref` is also valid when destructuring a struct.
let _copy_of_x = {
// `ref_to_x` is a reference to the `x` field of `point`.
let Point { x: ref ref_to_x, y: _ } = point;

// Return a copy of the `x` field of `point`.
*ref_to_x
};

// A mutable copy of `point`
let mut mutable_point = point;

{
// `ref` can be paired with `mut` to take mutable references.
let Point { x: _, y: ref mut mut_ref_to_y } = mutable_point;

// Mutate the `y` field of `mutable_point` via a mutable reference.
*mut_ref_to_y = 1;
}

println!("point is ({}, {})", point.x, point.y);
println!("mutable_point is ({}, {})", mutable_point.x, mutable_point.y);

// A mutable tuple that includes a pointer
let mut mutable_tuple = (Box::new(5u32), 3u32);

{
// Destructure `mutable_tuple` to change the value of `last`.
let (_, ref mut last) = mutable_tuple;
*last = 2u32;
}

println!("tuple is {:?}", mutable_tuple);
}

# What is the difference between immutable and const variables in Rust?

const, in Rust, is short for constant and is related to compile-time evaluation. It shows up:

  • when declaring constants: const FOO: usize = 3;
  • when declaring compile-time evaluable functions: const fn foo() -> &'static str

These kinds of values can be used as generic parameters: [u8; FOO]. For now this is limited to array size, but there is talk, plans, and hope to extend it further in the future.

By contrast, a let binding is about a run-time computed value.

Note that despite mut being used because the concept of mutability is well-known, Rust actually lies here. &T and &mut T are about aliasing, not mutability:

  • &T: shared reference
  • &mut T: unique reference

Most notably, some types feature interior mutability and can be mutated via &T (shared references): Cell, RefCell, Mutex, etc.

Edited on