# 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:
- 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 callself.next()— next comes from Iterator, not from IteratorExt:
I also wroteSelf::Itemfreely — that associated type comes from Iterator too.
Drop the : Iterator, and bothself.next()andSelf::Itemstop compiling, because nothing guarantees Self has them. - 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 | mod ext { |
# 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 | fn main () { |
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 | fn main() { |
# Why the size for values of type [u8] cannot be known at compilation time?
1 | // @ the size for values of type `[u8]` cannot be known at compilation time, the trait `std::marker::Sized` is not implemented for `[u8]` |
# How to open file with open and write mode ?
1 | // File::open open file only read mode, so write content will PermissionDenied |
# What mean of ref & ref mut below?
1 | let mut x = 5; |
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 |
|
# 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.