main.rs
6.87 KB
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//
// Examples related to ownership, also introducing String.
//
// Georg Hopp <georg@steffers.org>
//
// Copyright © 2019 Georg Hopp
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
fn main() {
concat();
move_variable();
clone_variable();
let s = String::from("hello"); // s comes into scope
take_ownership(s); // s's value moves into the function
// … and so is no longer valid here.
let x = 5; // x comes into scope
makes_copy(x); // the scalar value has the Copy trait and
// lives on the stack and thus is still
// valid here.
let _s1 = gives_ownership(); // move the return value into _s1
let s2 = String::from("hello"); // s2 comes into scope
let _s3 = takes_and_gives(s2); // s2 is moved into function, which in
// turn moves the return value into _s3.
let s1 = String::from("hello"); // s1 comes into scope.
let len = calculate_length(&s1); // A reference to s1 is given to a
// calculate_length which effectively is
// not s1 itself but another pointer to
// s1… which is the reason that we still
// can use it below.
let _another_s = &s1; // again only a reference which does not
// take ownership, thus s1 can still be
// used below.
println!("The length of '{}' is {}.", s1, len);
// Passing values as reference to a function is called borrowing. A
// borrowed value can't be changed.
change(&s1);
// but we can force this… which is probably not the best of ideas most
// of the time…
let mut s_mut = String::from("hello");
change_mutable(&mut s_mut);
// but you can have only one mutable reference of a value in a single
// scope. The following would fail with:
// cannot borrow `s_mut` as mutable more than once at a time second
// mutable borrow occurs here
// let r1 = &mut s_mut;
// let r2 = &mut s_mut;
// println!("{}, {}", r1, r2);
// We also can't have an immutable reference while we have a mutable one.
// Look on Page 98 for an explanation.
// The scope of references is not the whole block they are introduced in
// but goes only until their last usage. Thus if you first have an
// immutable reference but never use it after a mutable reference is
// declared, that would be ok… At all this is kind of confusing and very
// Mozzilaish. :D
// Now we demonstrate string slices…
let s4 = String::from("hello world");
let s_slice = first_word(&s4);
// working with an mutable reference like with s4.clear() will not
// compile at this point because we already have and use later on an
// immutable reference.
println!("The slice was: {}", s_slice);
// not that string literals are slices. They are immutable references of
// the programs TEXT segment. Thats the reason why they are immutable.
// Thus try generic_first_word…
println!("First word on literal: {}", generic_first_word("hello world"));
println!("First word on String: {}", generic_first_word(&s4[..]));
} // x and s go out of scope but nothing happens for s because this function
// has no longer the ownership of s.
// s3 goes out of scope and is dropped. s2 was moved and s1 is dropped.
fn concat() {
let mut s = String::from("hello");
s.push_str(", world!");
println!("{}", s);
}
fn move_variable() {
let s1 = String::from("hello");
let s2 = s1; // does not copy data but only the String structure.
// when using s1 below we get an error that a moved value was borrowed.
println!("{}, world!", s2);
}
fn clone_variable() {
let s1 = String::from("hello");
let s2 = s1.clone();
// this time both are valid.
println!("s1 = {}, s2 = {}", s1, s2)
}
fn take_ownership(some_string: String) { // some_string comes into scope
println!("{}", some_string);
} // some_string goes out of scope and «drop» is called, thus memory freed.
fn makes_copy(some_integer: i32) { // some integer comes into scope
println!("{}", some_integer);
} // Here, some_integer goes out of scope but because it was a copy and on the
// stack nothing special happens… beside that stack space is freed.
fn gives_ownership() -> String { // this will move the return value into the
// calling function.
let some_string = String::from("hello"); // some_string comes into scope
some_string
}
fn takes_and_gives(a_string: String) -> String { // a_string comes into scope
a_string // and is returned and moved
// to the calling function.
} // a_string goes out of scope but nothing happens as it is moved.
fn calculate_length(s: &String) -> usize { // s comes into scope. It is a
// reference. References do not
// take ownership of the underlying
// value which is the String in
// main.
s.len()
} // Here s goes out of scope but because it has no ownership of the String
// nothing happens.
fn change(_some_string: &String) {
// the following would give this error:
// `_some_string` is a `&` reference, so the data it refers to cannot be
// borrowed as mutable
// _some_string.push_str(", world!");
}
fn change_mutable(some_string: &mut String) {
some_string.push_str(", world");
}
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[..i];
}
}
&s[..]
}
// To make first_word work on either string literals (which are in fact string
// slices, s.o.) one would write first_word like this…
fn generic_first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[..i];
}
}
&s[..]
}