郭⾄至軒 [:kuoe0]
Mozilla
kuoe0.tw@gmail.com
Ownership
System in Rust
2016/07/12 @摩茲⼯工寮
4.8 Ownership[link]
Variable & Memory
A variable name is only a name.
It’s possible that a variable name can not access any
memory.
When a variable is declared, Rust allocates memory in
stack and heap (if need) for it.
When the owner of resources is destroyed, ALL
resources it owned would be released.
Variable & Memory
Stack
Heap
fn main() {
let v = vec![1, 2, 3];
}
dynamic memory
static memory
Variable & Memory
Stack
Heap
fn main() {
let v = vec![1, 2, 3];
}
dynamic memory
static memory
When the variable is destroyed…
fn main() {
let v = vec![1, 2, 3];
}
Variable & Memory
Stack
Heap
dynamic memory
static memory
All related resources will be destroyed, too!
Move By Default
Assignment operator is move semantics by default.
There is exactly one variable binding to any resource.
Avoid data racing to guarantee data consistency.
Move By Default
struct Point {
x: i32,
y: i32
}
fn main() {
let v1 = Point{ x: 10, y:
20};
let v2 = v1;
println!("{}", v1.x);
}
error: use of moved value: `v1.x` [--explain
E0382]
--> <anon>:9:20
8 |> let v2 = v1;
|> -- value moved here
9 |> println!("{}", v1.x);
|> ^^^^ value used here
after move
<std macros>:2:27: 2:58: note: in this
expansion of format_args!
<std macros>:3:1: 3:54: note: in this
expansion of print! (defined in <std macros>)
<anon>:9:5: 9:26: note: in this expansion of
println! (defined in <std macros>)
note: move occurs because `v1` has type
`Point`, which does not implement the `Copy`
trait
error: aborting due to previous error
compile
Move By Default
struct Point {
x: i32,
y: i32
}
fn main() {
let v1 = Point{ x: 10, y:
20};
let v2 = v1;
println!("{}", v1.x);
}
error: use of moved value: `v1.x` [--explain
E0382]
--> <anon>:9:20
8 |> let v2 = v1;
|> -- value moved here
9 |> println!("{}", v1.x);
|> ^^^^ value used here
after move
<std macros>:2:27: 2:58: note: in this
expansion of format_args!
<std macros>:3:1: 3:54: note: in this
expansion of print! (defined in <std macros>)
<anon>:9:5: 9:26: note: in this expansion of
println! (defined in <std macros>)
note: move occurs because `v1` has type
`Point`, which does not implement the `Copy`
trait
error: aborting due to previous error
compile
Use of moved value!
v1.x
Move By Default
stack
struct Point {
x: i32,
y: i32
}
fn main() {
let v1 = Point{ x: 10, y:
20};
let v2 = v1;
println!("{}", v1.x);
}
Point { x = 10, y = 20 }
names
v1
Move By Default
stack
struct Point {
x: i32,
y: i32
}
fn main() {
let v1 = Point{ x: 10, y:
20};
let v2 = v1;
println!("{}", v1.x);
}
Point { x = 10, y = 20 }
names
v1
v2
Copyable Type
The types which implement Copy trait can make
assignment operator be copy semantics.
Allow to use the variable which be copied.
All primitive types implement the Copy trait.
Copyable Type
fn main() {
let v1 = 10;
let v2 = v1;
println!("v1 = {}", v1);
println!("v2 = {}", v2);
}
v1 = 10
v2 = 10
Program ended.
run
Copyable Type
fn main() {
let v1 = 10;
let v2 = v1;
println!("v1 = {}", v1);
println!("v2 = {}", v2);
}
stacknames
v1 i32 { 10 }
Copyable Type
fn main() {
let v1 = 10;
let v2 = v1;
println!("v1 = {}", v1);
println!("v2 = {}", v2);
}
stacknames
v1 i32 { 10 }
v2 i32 { 10 }
Parameter Passing
Passing parameters is also move semantics by default
(no Copy trait).
Developers should return the ownership of parameters
by themselves.
Yes, you should return ten variables back if you pass
ten parameters into a function. 😜
Parameter Passing
struct Pt { x: i32, y: i32 }
fn dist(v: Pt) -> Pt {
println!("{}", v.x * v.x + v.y *
v.y);
v
}
fn main() {
let v = Pt{ x: 3, y: 4 };
let v = dist(v);
println!("{} {}", v.x, v.y);
}
struct Pt { x: i32, y: i32 }
fn dot(v1: Pt, v2: Pt) -> (Pt, Pt) {
println!("{}", v1.x * v2.x +
v1.y * v2.y);
(v1, v2)
}
fn main() {
let v1 = Pt{ x: 3, y: 4 };
let v2 = Pt{ x: 1, y: 2 };
let (v1, v2) = dot(v1, v2);
println!("{} {}", v1.x, v1.y);
println!("{} {}", v2.x, v2.y);
}
one parameter two parameters
Parameter Passing
struct Pt { x: i32 }
fn square(v: Pt) {
println!("{}", v.x * v.x);
}
fn main() {
let v = Pt{ x: 3 };
square(v);
println!("{}", v.x);
}
error: use of moved value: `v.x` [--explain
E0382]
--> <anon>:10:20
9 |> square(v);
|> - value moved here
10 |> println!("{}", v.x);
|> ^^^ value used here
after move
<std macros>:2:27: 2:58: note: in this
expansion of format_args!
<std macros>:3:1: 3:54: note: in this
expansion of print! (defined in <std macros>)
<anon>:10:5: 10:25: note: in this expansion
of println! (defined in <std macros>)
note: move occurs because `v` has type `Pt`,
which does not implement the `Copy` trait
error: aborting due to previous error
compile
Parameter Passing
struct Pt { x: i32 }
fn square(v: Pt) {
println!("{}", v.x * v.x);
}
fn main() {
let v = Pt{ x: 3 };
square(v);
println!("{}", v.x);
}
error: use of moved value: `v.x` [--explain
E0382]
--> <anon>:10:20
9 |> square(v);
|> - value moved here
10 |> println!("{}", v.x);
|> ^^^ value used here
after move
<std macros>:2:27: 2:58: note: in this
expansion of format_args!
<std macros>:3:1: 3:54: note: in this
expansion of print! (defined in <std macros>)
<anon>:10:5: 10:25: note: in this expansion
of println! (defined in <std macros>)
note: move occurs because `v` has type `Pt`,
which does not implement the `Copy` trait
error: aborting due to previous error
compile
v.x
Use of moved value!
4.9 Reference and Borrowing[link]
Syntax of Reference
fn main() {
let a = 1;
let b = &a; // &a is the reference to a
let mut c = 2;
let d = &mut c; // &mut c is the mutable
reference to c
}
Borrowing
Use the references to borrow the ownership.
The ownership will return to original owner when the
borrower is destroyed automatically.
References are immutable.
Allow multiple references to one variable.
A borrowed variable can be read but not written.
Only allow to borrow the variable with longer lifetime.
Borrowing
fn main() {
let orig = 0;
let b1 = &orig;
let b2 = &orig;
let b3 = &orig;
println!("b1 = {}", b1);
println!("b2 = {}", b2);
println!("b3 = {}", b3);
println!("orig = {}", orig);
}
b1 = 0
b2 = 0
b3 = 0
orig = 0
Program ended.
run
Borrowing
fn main() {
let mut x = 0;
{
let y = &x;
x += 1;
println!("{}", y);
}
println!("{}", x);
}
error: cannot assign to `x` because it is
borrowed [--explain E0506]
--> <anon>:5:9
4 |> let y = &x;
|> - borrow of `x` occurs
here
5 |> x += 1;
|> ^^^^^^ assignment to borrowed
`x` occurs here
error: aborting due to previous error
compile
Borrowing
fn main() {
let mut x = 0;
{
let y = &x;
x += 1;
println!("{}", y);
}
println!("{}", x);
}
error: cannot assign to `x` because it is
borrowed [--explain E0506]
--> <anon>:5:9
4 |> let y = &x;
|> - borrow of `x` occurs
here
5 |> x += 1;
|> ^^^^^^ assignment to borrowed
`x` occurs here
error: aborting due to previous error
compile
x += 1;
Cannot write the borrowed variable!
Borrowing
fn main() {
let y: &i32;
{
let x = 5;
y = &x;
}
println!("{}", y);
}
error: `x` does not live long enough
--> <anon>:5:14
5 |> y = &x;
|> ^
note: reference must be valid for the block
suffix following statement 0 at 2:16...
--> <anon>:2:17
2 |> let y: &i32;
|> ^
note: ...but borrowed value is only valid for
the block suffix following statement 0 at
4:18
--> <anon>:4:19
4 |> let x = 5;
|> ^
error: aborting due to previous error
compile
Borrowing
fn main() {
let y: &i32;
{
let x = 5;
y = &x;
}
println!("{}", y);
}
error: `x` does not live long enough
--> <anon>:5:14
5 |> y = &x;
|> ^
note: reference must be valid for the block
suffix following statement 0 at 2:16...
--> <anon>:2:17
2 |> let y: &i32;
|> ^
note: ...but borrowed value is only valid for
the block suffix following statement 0 at
4:18
--> <anon>:4:19
4 |> let x = 5;
|> ^
error: aborting due to previous error
compile
y = &x;
Lifetime of x is shorter than y.
Borrowing
fn main() {
let y: &i32;
let x = 5;
y = &x;
println!("{}", y);
}
error: `x` does not live long enough
--> <anon>:4:10
4 |> y = &x;
|> ^
note: reference must be valid for the block
suffix following statement 0 at 2:16...
--> <anon>:2:17
2 |> let y: &i32;
|> ^
note: ...but borrowed value is only valid for
the block suffix following statement 1 at
3:14
--> <anon>:3:15
3 |> let x = 5;
|> ^
error: aborting due to previous error
compile
Borrowing
fn main() {
let y: &i32;
let x = 5;
y = &x;
println!("{}", y);
}
error: `x` does not live long enough
--> <anon>:4:10
4 |> y = &x;
|> ^
note: reference must be valid for the block
suffix following statement 0 at 2:16...
--> <anon>:2:17
2 |> let y: &i32;
|> ^
note: ...but borrowed value is only valid for
the block suffix following statement 1 at
3:14
--> <anon>:3:15
3 |> let x = 5;
|> ^
error: aborting due to previous error
compile
y = &x;
Lifetime of x is shorter than y.
Borrowing
struct Pt { x: i32, y: i32 }
fn dot(v1: Pt, v2: Pt) -> (Pt, Pt) {
println!("{}", v1.x * v2.x +
v1.y * v2.y);
(v1, v2)
}
fn main() {
let v1 = Pt{ x: 3, y: 4 };
let v2 = Pt{ x: 1, y: 2 };
let (v1, v2) = dot(v1, v2);
println!("{} {}", v1.x, v1.y);
println!("{} {}", v2.x, v2.y);
}
struct Pt { x: i32, y: i32 }
fn dot(v1: &Pt, v2: &Pt) {
println!("{}", v1.x * v2.x +
v1.y * v2.y);
}
fn main() {
let v1 = Pt{ x: 3, y: 4 };
let v2 = Pt{ x: 1, y: 2 };
dot(&v1, &v2);
println!("{} {}", v1.x, v1.y);
println!("{} {}", v2.x, v2.y);
}
Borrowing
struct Pt { x: i32, y: i32 }
fn dot(v1: Pt, v2: Pt) -> (Pt, Pt) {
println!("{}", v1.x * v2.x +
v1.y * v2.y);
(v1, v2)
}
fn main() {
let v1 = Pt{ x: 3, y: 4 };
let v2 = Pt{ x: 1, y: 2 };
let (v1, v2) = dot(v1, v2);
println!("{} {}", v1.x, v1.y);
println!("{} {}", v2.x, v2.y);
}
struct Pt { x: i32, y: i32 }
fn dot(v1: &Pt, v2: &Pt) {
println!("{}", v1.x * v2.x +
v1.y * v2.y);
}
fn main() {
let v1 = Pt{ x: 3, y: 4 };
let v2 = Pt{ x: 1, y: 2 };
dot(&v1, &v2);
println!("{} {}", v1.x, v1.y);
println!("{} {}", v2.x, v2.y);
}
Mutable Borrowing
Use mutable references only if you need to change the values
you borrowed.
Only allow to borrow a mutable variables as a mutable
reference.
There is exactly one mutable reference to a variable.
A variable borrowed as a mutable reference can not be
borrowed as immutable references.
A variable borrowed as a mutable reference can not be used
until the end of borrowing.
Mutable Borrowing
fn main() {
let mut x = 0;
{
let y = &mut x;
*y += 1;
}
println!("x = {}", x);
}
x = 1
Program ended.
run
Mutable Borrowing
fn main() {
let mut x = 0;
{
let y = &mut x;
let z = &mut x;
*y += 1;
}
println!("x = {}", x);
}
error: cannot borrow `x` as mutable more than
once at a time [--explain E0499]
--> <anon>:5:22
4 |> let y = &mut x;
|> - first mutable
borrow occurs here
5 |> let z = &mut x;
|> ^ second mutable
borrow occurs here
6 |> *y += 1;
7 |> }
|> - first borrow ends here
error: aborting due to previous error
compile
Mutable Borrowing
fn main() {
let mut x = 0;
{
let y = &mut x;
let z = &mut x;
*y += 1;
}
println!("x = {}", x);
}
error: cannot borrow `x` as mutable more than
once at a time [--explain E0499]
--> <anon>:5:22
4 |> let y = &mut x;
|> - first mutable
borrow occurs here
5 |> let z = &mut x;
|> ^ second mutable
borrow occurs here
6 |> *y += 1;
7 |> }
|> - first borrow ends here
error: aborting due to previous error
compile
let z = &mut x;
Cannot borrow x as mutable reference more than once!
Mutable Borrowing
fn main() {
let mut x = 0;
{
let y = &mut x;
let z = &x;
*y += 1;
}
println!("x = {}", x);
}
error: cannot borrow `x` as immutable because
it is also borrowed as mutable [--explain
E0502]
--> <anon>:6:18
4 |> let y = &mut x;
|> - mutable borrow
occurs here
5 |> *y += 1;
6 |> let z = &x;
|> ^ immutable borrow
occurs here
7 |> }
|> - mutable borrow ends here
error: aborting due to previous error
compile
Mutable Borrowing
fn main() {
let mut x = 0;
{
let y = &mut x;
let z = &x;
*y += 1;
}
println!("x = {}", x);
}
error: cannot borrow `x` as immutable because
it is also borrowed as mutable [--explain
E0502]
--> <anon>:6:18
4 |> let y = &mut x;
|> - mutable borrow
occurs here
5 |> *y += 1;
6 |> let z = &x;
|> ^ immutable borrow
occurs here
7 |> }
|> - mutable borrow ends here
error: aborting due to previous error
compile
let z = &x;
Cannot borrow the variable been borrowed as a mutable reference!
Mutable Borrowing
fn main() {
let mut x = 0;
{
let y = &mut x;
let z = x + 1;
}
println!("x = {}", x);
}
error: cannot use `x` because it was mutably
borrowed [E0503]
--> <anon>:5:17
5 |> let z = x + 1;
|> ^
note: borrow of `x` occurs here
--> <anon>:4:22
4 |> let y = &mut x;
|> ^
error: aborting due to previous error
compile
Mutable Borrowing
fn main() {
let mut x = 0;
{
let y = &mut x;
let z = x + 1;
}
println!("x = {}", x);
}
error: cannot use `x` because it was mutably
borrowed [E0503]
--> <anon>:5:17
5 |> let z = x + 1;
|> ^
note: borrow of `x` occurs here
--> <anon>:4:22
4 |> let y = &mut x;
|> ^
error: aborting due to previous error
compile
let z = x + 1;
Cannot access the variable been borrowed as a mutable reference.
Thinking in Scopes
fn main() {
let mut x = 0;
let y = &mut x;
*y += 1;
println!("x = {}", x);
}
Why compile error?
Thinking in Scopes(cont’)
fn main() {
let mut x = 0;
let y = &mut x;
*y += 1;
println!("x = {}", x);
}
error: cannot borrow `x` as immutable because
it is also borrowed as mutable [--explain
E0502]
--> <anon>:5:24
3 |> let y = &mut x;
|> - mutable borrow occurs
here
4 |> *y += 1;
5 |> println!("x = {}", x);
|> ^ immutable
borrow occurs here
6 |> }
|> - mutable borrow ends here
<std macros>:2:27: 2:58: note: in this
expansion of format_args!
<std macros>:3:1: 3:54: note: in this
expansion of print! (defined in <std macros>)
<anon>:5:5: 5:27: note: in this expansion of
println! (defined in <std macros>)
error: aborting due to previous error
compile
Thinking in Scopes(cont’)
fn main() {
let mut x = 0;
let y = &mut x;
*y += 1;
println!("x = {}", x);
}
error: cannot borrow `x` as immutable because
it is also borrowed as mutable [--explain
E0502]
--> <anon>:5:24
3 |> let y = &mut x;
|> - mutable borrow occurs
here
4 |> *y += 1;
5 |> println!("x = {}", x);
|> ^ immutable
borrow occurs here
6 |> }
|> - mutable borrow ends here
<std macros>:2:27: 2:58: note: in this
expansion of format_args!
<std macros>:3:1: 3:54: note: in this
expansion of print! (defined in <std macros>)
<anon>:5:5: 5:27: note: in this expansion of
println! (defined in <std macros>)
error: aborting due to previous error
compile
println!("x = {}", x);
Immutable borrow occurs here!
Iterator Invalidation
fn main() {
let mut v = vec![1, 2, 3];
for i in &v {
println!("{}", i);
v.push(34);
}
}
error: cannot borrow `v` as mutable because
it is also borrowed as immutable [--explain
E0502]
--> <anon>:6:9
4 |> for i in &v {
|> - immutable borrow occurs
here
5 |> println!("{}", i);
6 |> v.push(34);
|> ^ mutable borrow occurs here
7 |> }
|> - immutable borrow ends here
error: aborting due to previous error
compile
Iterator Invalidation
fn main() {
let mut v = vec![1, 2, 3];
for i in &v {
println!("{}", i);
v.push(34);
}
}
error: cannot borrow `v` as mutable because
it is also borrowed as immutable [--explain
E0502]
--> <anon>:6:9
4 |> for i in &v {
|> - immutable borrow occurs
here
5 |> println!("{}", i);
6 |> v.push(34);
|> ^ mutable borrow occurs here
7 |> }
|> - immutable borrow ends here
error: aborting due to previous error
compile
v.push(34);
push(&mut self, …) try to borrow v as a mutable reference!
4.10 Lifetimes[link]
Syntax of Lifetimes Specifier
fn fn2<'a>(x: &'a i32) -> &'a i32 {
// do something
}
Syntax of Lifetimes Specifier
fn fn2<'a>(x: &'a i32) -> &'a i32 {
// do something
}
'a 'a 'a
input lifetime output lifetime
Syntax of Lifetimes Specifier
// lifetime with mutable reference
fn foo<'a>(x: &'a mut i32) -> &'a mut i32 {
// do something
}
// lifetime in struct
struct Foo<'a> {
x: &'a i32
}
// lifetime with impl
impl<'a> Foo<'a> {
fn x(&self) -> &'a i32 { self.x }
}
Lifetimes Specifier
All references need lifetimes.
Explicit lifetimes are used to make lifetime inference
unambiguous.
Must give explicit lifetimes for struct contain reference
members.
No need to give explicit lifetimes to the functions
without references return.
Lifetimes Specifier
struct Foo<'a> {
x: &'a i32
}
impl<'a> Foo<'a> {
fn x(&self) -> &'a i32 { self.x }
}
fn main() {
let y = 5;
let f = Foo { x: &y };
println!("{}", f.x);
println!("{}", f.x());
}
5
5
Program ended.
run
Lifetime Inference
Each elided lifetime of arguments becomes a distinct
lifetime parameter.
If there is exactly one input lifetime, all elided lifetimes
of the return values will be as same as the input
lifetime.
If there is &self in input lifetimes, all elided lifetimes of
the return values will be as same as &self.
Lifetime Inference (valid)
fn print(s: &str); // elided
fn print<'a>(s: &'a str); // expanded
//////////
fn substr(s: &str, until: u32) -> &str; // elided
fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded
//////////
fn get_mut(&mut self) -> &mut T; // elided
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
Lifetime Inference (invalid)
fn get_str() -> &str; // ILLEGAL, no inputs
//////////
fn frob(s: &str, t: &str) -> &str; // Two input
lifetimes
fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Output
lifetime is ambiguous
Static Lifetime
Some resources have the lifetime of the entire
program.
No need to give explicit lifetime for functions return
static resources.
Lifetimes Specifier
static FIVE: i32 = 5;
fn get_five() -> &'static i32 {
&FIVE
}
fn main() {
let x = get_five();
println!("x = {}", x);
}
x = 5
Program ended.
run
Thanks!
CC-BY-SA

Ownership System in Rust

  • 1.
  • 2.
  • 3.
    Variable & Memory Avariable name is only a name. It’s possible that a variable name can not access any memory. When a variable is declared, Rust allocates memory in stack and heap (if need) for it. When the owner of resources is destroyed, ALL resources it owned would be released.
  • 4.
    Variable & Memory Stack Heap fnmain() { let v = vec![1, 2, 3]; } dynamic memory static memory
  • 5.
    Variable & Memory Stack Heap fnmain() { let v = vec![1, 2, 3]; } dynamic memory static memory When the variable is destroyed…
  • 6.
    fn main() { letv = vec![1, 2, 3]; } Variable & Memory Stack Heap dynamic memory static memory All related resources will be destroyed, too!
  • 7.
    Move By Default Assignmentoperator is move semantics by default. There is exactly one variable binding to any resource. Avoid data racing to guarantee data consistency.
  • 8.
    Move By Default structPoint { x: i32, y: i32 } fn main() { let v1 = Point{ x: 10, y: 20}; let v2 = v1; println!("{}", v1.x); } error: use of moved value: `v1.x` [--explain E0382] --> <anon>:9:20 8 |> let v2 = v1; |> -- value moved here 9 |> println!("{}", v1.x); |> ^^^^ value used here after move <std macros>:2:27: 2:58: note: in this expansion of format_args! <std macros>:3:1: 3:54: note: in this expansion of print! (defined in <std macros>) <anon>:9:5: 9:26: note: in this expansion of println! (defined in <std macros>) note: move occurs because `v1` has type `Point`, which does not implement the `Copy` trait error: aborting due to previous error compile
  • 9.
    Move By Default structPoint { x: i32, y: i32 } fn main() { let v1 = Point{ x: 10, y: 20}; let v2 = v1; println!("{}", v1.x); } error: use of moved value: `v1.x` [--explain E0382] --> <anon>:9:20 8 |> let v2 = v1; |> -- value moved here 9 |> println!("{}", v1.x); |> ^^^^ value used here after move <std macros>:2:27: 2:58: note: in this expansion of format_args! <std macros>:3:1: 3:54: note: in this expansion of print! (defined in <std macros>) <anon>:9:5: 9:26: note: in this expansion of println! (defined in <std macros>) note: move occurs because `v1` has type `Point`, which does not implement the `Copy` trait error: aborting due to previous error compile Use of moved value! v1.x
  • 10.
    Move By Default stack structPoint { x: i32, y: i32 } fn main() { let v1 = Point{ x: 10, y: 20}; let v2 = v1; println!("{}", v1.x); } Point { x = 10, y = 20 } names v1
  • 11.
    Move By Default stack structPoint { x: i32, y: i32 } fn main() { let v1 = Point{ x: 10, y: 20}; let v2 = v1; println!("{}", v1.x); } Point { x = 10, y = 20 } names v1 v2
  • 12.
    Copyable Type The typeswhich implement Copy trait can make assignment operator be copy semantics. Allow to use the variable which be copied. All primitive types implement the Copy trait.
  • 13.
    Copyable Type fn main(){ let v1 = 10; let v2 = v1; println!("v1 = {}", v1); println!("v2 = {}", v2); } v1 = 10 v2 = 10 Program ended. run
  • 14.
    Copyable Type fn main(){ let v1 = 10; let v2 = v1; println!("v1 = {}", v1); println!("v2 = {}", v2); } stacknames v1 i32 { 10 }
  • 15.
    Copyable Type fn main(){ let v1 = 10; let v2 = v1; println!("v1 = {}", v1); println!("v2 = {}", v2); } stacknames v1 i32 { 10 } v2 i32 { 10 }
  • 16.
    Parameter Passing Passing parametersis also move semantics by default (no Copy trait). Developers should return the ownership of parameters by themselves. Yes, you should return ten variables back if you pass ten parameters into a function. 😜
  • 17.
    Parameter Passing struct Pt{ x: i32, y: i32 } fn dist(v: Pt) -> Pt { println!("{}", v.x * v.x + v.y * v.y); v } fn main() { let v = Pt{ x: 3, y: 4 }; let v = dist(v); println!("{} {}", v.x, v.y); } struct Pt { x: i32, y: i32 } fn dot(v1: Pt, v2: Pt) -> (Pt, Pt) { println!("{}", v1.x * v2.x + v1.y * v2.y); (v1, v2) } fn main() { let v1 = Pt{ x: 3, y: 4 }; let v2 = Pt{ x: 1, y: 2 }; let (v1, v2) = dot(v1, v2); println!("{} {}", v1.x, v1.y); println!("{} {}", v2.x, v2.y); } one parameter two parameters
  • 18.
    Parameter Passing struct Pt{ x: i32 } fn square(v: Pt) { println!("{}", v.x * v.x); } fn main() { let v = Pt{ x: 3 }; square(v); println!("{}", v.x); } error: use of moved value: `v.x` [--explain E0382] --> <anon>:10:20 9 |> square(v); |> - value moved here 10 |> println!("{}", v.x); |> ^^^ value used here after move <std macros>:2:27: 2:58: note: in this expansion of format_args! <std macros>:3:1: 3:54: note: in this expansion of print! (defined in <std macros>) <anon>:10:5: 10:25: note: in this expansion of println! (defined in <std macros>) note: move occurs because `v` has type `Pt`, which does not implement the `Copy` trait error: aborting due to previous error compile
  • 19.
    Parameter Passing struct Pt{ x: i32 } fn square(v: Pt) { println!("{}", v.x * v.x); } fn main() { let v = Pt{ x: 3 }; square(v); println!("{}", v.x); } error: use of moved value: `v.x` [--explain E0382] --> <anon>:10:20 9 |> square(v); |> - value moved here 10 |> println!("{}", v.x); |> ^^^ value used here after move <std macros>:2:27: 2:58: note: in this expansion of format_args! <std macros>:3:1: 3:54: note: in this expansion of print! (defined in <std macros>) <anon>:10:5: 10:25: note: in this expansion of println! (defined in <std macros>) note: move occurs because `v` has type `Pt`, which does not implement the `Copy` trait error: aborting due to previous error compile v.x Use of moved value!
  • 20.
    4.9 Reference andBorrowing[link]
  • 21.
    Syntax of Reference fnmain() { let a = 1; let b = &a; // &a is the reference to a let mut c = 2; let d = &mut c; // &mut c is the mutable reference to c }
  • 22.
    Borrowing Use the referencesto borrow the ownership. The ownership will return to original owner when the borrower is destroyed automatically. References are immutable. Allow multiple references to one variable. A borrowed variable can be read but not written. Only allow to borrow the variable with longer lifetime.
  • 23.
    Borrowing fn main() { letorig = 0; let b1 = &orig; let b2 = &orig; let b3 = &orig; println!("b1 = {}", b1); println!("b2 = {}", b2); println!("b3 = {}", b3); println!("orig = {}", orig); } b1 = 0 b2 = 0 b3 = 0 orig = 0 Program ended. run
  • 24.
    Borrowing fn main() { letmut x = 0; { let y = &x; x += 1; println!("{}", y); } println!("{}", x); } error: cannot assign to `x` because it is borrowed [--explain E0506] --> <anon>:5:9 4 |> let y = &x; |> - borrow of `x` occurs here 5 |> x += 1; |> ^^^^^^ assignment to borrowed `x` occurs here error: aborting due to previous error compile
  • 25.
    Borrowing fn main() { letmut x = 0; { let y = &x; x += 1; println!("{}", y); } println!("{}", x); } error: cannot assign to `x` because it is borrowed [--explain E0506] --> <anon>:5:9 4 |> let y = &x; |> - borrow of `x` occurs here 5 |> x += 1; |> ^^^^^^ assignment to borrowed `x` occurs here error: aborting due to previous error compile x += 1; Cannot write the borrowed variable!
  • 26.
    Borrowing fn main() { lety: &i32; { let x = 5; y = &x; } println!("{}", y); } error: `x` does not live long enough --> <anon>:5:14 5 |> y = &x; |> ^ note: reference must be valid for the block suffix following statement 0 at 2:16... --> <anon>:2:17 2 |> let y: &i32; |> ^ note: ...but borrowed value is only valid for the block suffix following statement 0 at 4:18 --> <anon>:4:19 4 |> let x = 5; |> ^ error: aborting due to previous error compile
  • 27.
    Borrowing fn main() { lety: &i32; { let x = 5; y = &x; } println!("{}", y); } error: `x` does not live long enough --> <anon>:5:14 5 |> y = &x; |> ^ note: reference must be valid for the block suffix following statement 0 at 2:16... --> <anon>:2:17 2 |> let y: &i32; |> ^ note: ...but borrowed value is only valid for the block suffix following statement 0 at 4:18 --> <anon>:4:19 4 |> let x = 5; |> ^ error: aborting due to previous error compile y = &x; Lifetime of x is shorter than y.
  • 28.
    Borrowing fn main() { lety: &i32; let x = 5; y = &x; println!("{}", y); } error: `x` does not live long enough --> <anon>:4:10 4 |> y = &x; |> ^ note: reference must be valid for the block suffix following statement 0 at 2:16... --> <anon>:2:17 2 |> let y: &i32; |> ^ note: ...but borrowed value is only valid for the block suffix following statement 1 at 3:14 --> <anon>:3:15 3 |> let x = 5; |> ^ error: aborting due to previous error compile
  • 29.
    Borrowing fn main() { lety: &i32; let x = 5; y = &x; println!("{}", y); } error: `x` does not live long enough --> <anon>:4:10 4 |> y = &x; |> ^ note: reference must be valid for the block suffix following statement 0 at 2:16... --> <anon>:2:17 2 |> let y: &i32; |> ^ note: ...but borrowed value is only valid for the block suffix following statement 1 at 3:14 --> <anon>:3:15 3 |> let x = 5; |> ^ error: aborting due to previous error compile y = &x; Lifetime of x is shorter than y.
  • 30.
    Borrowing struct Pt {x: i32, y: i32 } fn dot(v1: Pt, v2: Pt) -> (Pt, Pt) { println!("{}", v1.x * v2.x + v1.y * v2.y); (v1, v2) } fn main() { let v1 = Pt{ x: 3, y: 4 }; let v2 = Pt{ x: 1, y: 2 }; let (v1, v2) = dot(v1, v2); println!("{} {}", v1.x, v1.y); println!("{} {}", v2.x, v2.y); } struct Pt { x: i32, y: i32 } fn dot(v1: &Pt, v2: &Pt) { println!("{}", v1.x * v2.x + v1.y * v2.y); } fn main() { let v1 = Pt{ x: 3, y: 4 }; let v2 = Pt{ x: 1, y: 2 }; dot(&v1, &v2); println!("{} {}", v1.x, v1.y); println!("{} {}", v2.x, v2.y); }
  • 31.
    Borrowing struct Pt {x: i32, y: i32 } fn dot(v1: Pt, v2: Pt) -> (Pt, Pt) { println!("{}", v1.x * v2.x + v1.y * v2.y); (v1, v2) } fn main() { let v1 = Pt{ x: 3, y: 4 }; let v2 = Pt{ x: 1, y: 2 }; let (v1, v2) = dot(v1, v2); println!("{} {}", v1.x, v1.y); println!("{} {}", v2.x, v2.y); } struct Pt { x: i32, y: i32 } fn dot(v1: &Pt, v2: &Pt) { println!("{}", v1.x * v2.x + v1.y * v2.y); } fn main() { let v1 = Pt{ x: 3, y: 4 }; let v2 = Pt{ x: 1, y: 2 }; dot(&v1, &v2); println!("{} {}", v1.x, v1.y); println!("{} {}", v2.x, v2.y); }
  • 32.
    Mutable Borrowing Use mutablereferences only if you need to change the values you borrowed. Only allow to borrow a mutable variables as a mutable reference. There is exactly one mutable reference to a variable. A variable borrowed as a mutable reference can not be borrowed as immutable references. A variable borrowed as a mutable reference can not be used until the end of borrowing.
  • 33.
    Mutable Borrowing fn main(){ let mut x = 0; { let y = &mut x; *y += 1; } println!("x = {}", x); } x = 1 Program ended. run
  • 34.
    Mutable Borrowing fn main(){ let mut x = 0; { let y = &mut x; let z = &mut x; *y += 1; } println!("x = {}", x); } error: cannot borrow `x` as mutable more than once at a time [--explain E0499] --> <anon>:5:22 4 |> let y = &mut x; |> - first mutable borrow occurs here 5 |> let z = &mut x; |> ^ second mutable borrow occurs here 6 |> *y += 1; 7 |> } |> - first borrow ends here error: aborting due to previous error compile
  • 35.
    Mutable Borrowing fn main(){ let mut x = 0; { let y = &mut x; let z = &mut x; *y += 1; } println!("x = {}", x); } error: cannot borrow `x` as mutable more than once at a time [--explain E0499] --> <anon>:5:22 4 |> let y = &mut x; |> - first mutable borrow occurs here 5 |> let z = &mut x; |> ^ second mutable borrow occurs here 6 |> *y += 1; 7 |> } |> - first borrow ends here error: aborting due to previous error compile let z = &mut x; Cannot borrow x as mutable reference more than once!
  • 36.
    Mutable Borrowing fn main(){ let mut x = 0; { let y = &mut x; let z = &x; *y += 1; } println!("x = {}", x); } error: cannot borrow `x` as immutable because it is also borrowed as mutable [--explain E0502] --> <anon>:6:18 4 |> let y = &mut x; |> - mutable borrow occurs here 5 |> *y += 1; 6 |> let z = &x; |> ^ immutable borrow occurs here 7 |> } |> - mutable borrow ends here error: aborting due to previous error compile
  • 37.
    Mutable Borrowing fn main(){ let mut x = 0; { let y = &mut x; let z = &x; *y += 1; } println!("x = {}", x); } error: cannot borrow `x` as immutable because it is also borrowed as mutable [--explain E0502] --> <anon>:6:18 4 |> let y = &mut x; |> - mutable borrow occurs here 5 |> *y += 1; 6 |> let z = &x; |> ^ immutable borrow occurs here 7 |> } |> - mutable borrow ends here error: aborting due to previous error compile let z = &x; Cannot borrow the variable been borrowed as a mutable reference!
  • 38.
    Mutable Borrowing fn main(){ let mut x = 0; { let y = &mut x; let z = x + 1; } println!("x = {}", x); } error: cannot use `x` because it was mutably borrowed [E0503] --> <anon>:5:17 5 |> let z = x + 1; |> ^ note: borrow of `x` occurs here --> <anon>:4:22 4 |> let y = &mut x; |> ^ error: aborting due to previous error compile
  • 39.
    Mutable Borrowing fn main(){ let mut x = 0; { let y = &mut x; let z = x + 1; } println!("x = {}", x); } error: cannot use `x` because it was mutably borrowed [E0503] --> <anon>:5:17 5 |> let z = x + 1; |> ^ note: borrow of `x` occurs here --> <anon>:4:22 4 |> let y = &mut x; |> ^ error: aborting due to previous error compile let z = x + 1; Cannot access the variable been borrowed as a mutable reference.
  • 40.
    Thinking in Scopes fnmain() { let mut x = 0; let y = &mut x; *y += 1; println!("x = {}", x); } Why compile error?
  • 41.
    Thinking in Scopes(cont’) fnmain() { let mut x = 0; let y = &mut x; *y += 1; println!("x = {}", x); } error: cannot borrow `x` as immutable because it is also borrowed as mutable [--explain E0502] --> <anon>:5:24 3 |> let y = &mut x; |> - mutable borrow occurs here 4 |> *y += 1; 5 |> println!("x = {}", x); |> ^ immutable borrow occurs here 6 |> } |> - mutable borrow ends here <std macros>:2:27: 2:58: note: in this expansion of format_args! <std macros>:3:1: 3:54: note: in this expansion of print! (defined in <std macros>) <anon>:5:5: 5:27: note: in this expansion of println! (defined in <std macros>) error: aborting due to previous error compile
  • 42.
    Thinking in Scopes(cont’) fnmain() { let mut x = 0; let y = &mut x; *y += 1; println!("x = {}", x); } error: cannot borrow `x` as immutable because it is also borrowed as mutable [--explain E0502] --> <anon>:5:24 3 |> let y = &mut x; |> - mutable borrow occurs here 4 |> *y += 1; 5 |> println!("x = {}", x); |> ^ immutable borrow occurs here 6 |> } |> - mutable borrow ends here <std macros>:2:27: 2:58: note: in this expansion of format_args! <std macros>:3:1: 3:54: note: in this expansion of print! (defined in <std macros>) <anon>:5:5: 5:27: note: in this expansion of println! (defined in <std macros>) error: aborting due to previous error compile println!("x = {}", x); Immutable borrow occurs here!
  • 43.
    Iterator Invalidation fn main(){ let mut v = vec![1, 2, 3]; for i in &v { println!("{}", i); v.push(34); } } error: cannot borrow `v` as mutable because it is also borrowed as immutable [--explain E0502] --> <anon>:6:9 4 |> for i in &v { |> - immutable borrow occurs here 5 |> println!("{}", i); 6 |> v.push(34); |> ^ mutable borrow occurs here 7 |> } |> - immutable borrow ends here error: aborting due to previous error compile
  • 44.
    Iterator Invalidation fn main(){ let mut v = vec![1, 2, 3]; for i in &v { println!("{}", i); v.push(34); } } error: cannot borrow `v` as mutable because it is also borrowed as immutable [--explain E0502] --> <anon>:6:9 4 |> for i in &v { |> - immutable borrow occurs here 5 |> println!("{}", i); 6 |> v.push(34); |> ^ mutable borrow occurs here 7 |> } |> - immutable borrow ends here error: aborting due to previous error compile v.push(34); push(&mut self, …) try to borrow v as a mutable reference!
  • 45.
  • 46.
    Syntax of LifetimesSpecifier fn fn2<'a>(x: &'a i32) -> &'a i32 { // do something }
  • 47.
    Syntax of LifetimesSpecifier fn fn2<'a>(x: &'a i32) -> &'a i32 { // do something } 'a 'a 'a input lifetime output lifetime
  • 48.
    Syntax of LifetimesSpecifier // lifetime with mutable reference fn foo<'a>(x: &'a mut i32) -> &'a mut i32 { // do something } // lifetime in struct struct Foo<'a> { x: &'a i32 } // lifetime with impl impl<'a> Foo<'a> { fn x(&self) -> &'a i32 { self.x } }
  • 49.
    Lifetimes Specifier All referencesneed lifetimes. Explicit lifetimes are used to make lifetime inference unambiguous. Must give explicit lifetimes for struct contain reference members. No need to give explicit lifetimes to the functions without references return.
  • 50.
    Lifetimes Specifier struct Foo<'a>{ x: &'a i32 } impl<'a> Foo<'a> { fn x(&self) -> &'a i32 { self.x } } fn main() { let y = 5; let f = Foo { x: &y }; println!("{}", f.x); println!("{}", f.x()); } 5 5 Program ended. run
  • 51.
    Lifetime Inference Each elidedlifetime of arguments becomes a distinct lifetime parameter. If there is exactly one input lifetime, all elided lifetimes of the return values will be as same as the input lifetime. If there is &self in input lifetimes, all elided lifetimes of the return values will be as same as &self.
  • 52.
    Lifetime Inference (valid) fnprint(s: &str); // elided fn print<'a>(s: &'a str); // expanded ////////// fn substr(s: &str, until: u32) -> &str; // elided fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded ////////// fn get_mut(&mut self) -> &mut T; // elided fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
  • 53.
    Lifetime Inference (invalid) fnget_str() -> &str; // ILLEGAL, no inputs ////////// fn frob(s: &str, t: &str) -> &str; // Two input lifetimes fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Output lifetime is ambiguous
  • 54.
    Static Lifetime Some resourceshave the lifetime of the entire program. No need to give explicit lifetime for functions return static resources.
  • 55.
    Lifetimes Specifier static FIVE:i32 = 5; fn get_five() -> &'static i32 { &FIVE } fn main() { let x = get_five(); println!("x = {}", x); } x = 5 Program ended. run
  • 56.