912 lines
35 KiB
Text
912 lines
35 KiB
Text
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Ownership\n",
|
||
"\n",
|
||
"* Memory is managed through a system of **ownership** with a set of rules that the compiler checks. \n",
|
||
"* If any of the rules are violated, the program won’t compile. \n",
|
||
"* None of the features of ownership will slow down your program while it’s running.\n",
|
||
"\n",
|
||
"## Ownership rules\n",
|
||
"\n",
|
||
"* Each value in Rust has an owner.\n",
|
||
"* There can only be one owner at a time.\n",
|
||
"* When the owner goes out of scope, the value will be dropped.\n",
|
||
"\n",
|
||
"## Variable scope\n",
|
||
"\n",
|
||
"* The **variable** is valid from the point at which it’s declared until the end of the current **scope**\n",
|
||
"* There are two important points in time here:\n",
|
||
" * when `s` comes into scope, it is valid.\n",
|
||
" * it remains valid until it goes out of scope."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Rusty Cage!\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"{\n",
|
||
" let mut s = String::from(\"Rusty\"); // s allocates memory on the heap\n",
|
||
" s.push_str(\" Cage!\"); // ... do something with 's'\n",
|
||
" println!(\"{}\", s);\n",
|
||
" \n",
|
||
"} // 's' goes out of scope, and memory is deallocated"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Copy & Move for objects"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Copy\n",
|
||
"\n",
|
||
"* If a type implements the `Copy` trait, variables that use it do not move, but rather are trivially copied, making them still valid after assignment to another variable.\n",
|
||
"\n",
|
||
"* Primitive types that implement `Copy` trait are:\n",
|
||
" * all the integer types, such as `u32`.\n",
|
||
" * the Boolean type, `bool`, with values `true` and `false`.\n",
|
||
" * all the floating-point types, such as `f64`.\n",
|
||
" * the character type, `char`.\n",
|
||
" * tuples, if they only contain types that also implement `Copy`. For example, `(i32, i32)` implements `Copy`, but `(i32, String)` does not.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"x=10; y=10\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let x = 10;\n",
|
||
"let y = x;\n",
|
||
"\n",
|
||
"println!(\"x={x}; y={y}\");"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Move\n",
|
||
"\n",
|
||
"* Objects that allocate memory on heap are moved by default (shallow copy is disabled by default)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Rusty\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let s1 = String::from(\"Rusty\");\n",
|
||
"let s2 = s1;\n",
|
||
"\n",
|
||
"println!(\"{s2}\");"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 17,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"ename": "Error",
|
||
"evalue": "borrow of moved value: `s1`",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[31m[E0382] Error:\u001b[0m borrow of moved value: `s1`",
|
||
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_17:1:1\u001b[38;5;246m]\u001b[0m",
|
||
" \u001b[38;5;246m│\u001b[0m",
|
||
" \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100m1\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mS\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mR\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
|
||
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m ",
|
||
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m move occurs because `s1` has type `String`, which does not implement the `Copy` trait",
|
||
" \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54m1\u001b[0m\u001b[38;5;249m;\u001b[0m",
|
||
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;68m│\u001b[0m ",
|
||
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m value moved here",
|
||
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;68m│\u001b[0m ",
|
||
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider cloning the value if the performance cost is acceptable: `.clone()`",
|
||
"\u001b[38;5;246m───╯\u001b[0m"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let s1 = String::from(\"Rusty\");\n",
|
||
"let s2 = s1;\n",
|
||
"\n",
|
||
"s1"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* How it works\n",
|
||
"\n",
|
||
"<img src=\"images/rust-move.png\" alt=\"rust-move\" height=\"400\" align=\"center\" />"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "rust"
|
||
}
|
||
},
|
||
"source": [
|
||
"* if we do want to make a deep copy the heap data of the `String`, not just the stack data, we can use a common method called `clone()`."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"s1 = hello, s2 = hello\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let s1 = String::from(\"hello\");\n",
|
||
"let s2 = s1.clone();\n",
|
||
"\n",
|
||
"println!(\"s1 = {s1}, s2 = {s2}\");"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"<img src=\"images/rust-clone.png\" alt=\"rust-clone\" height=\"400\" align=\"center\" />"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Move and Indexed Content\n",
|
||
"\n",
|
||
"* When we move a vector, the vector itself is moved, but its indexed content cannot be moved."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"ename": "Error",
|
||
"evalue": "cannot move out of index of `Vec<String>`",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[31m[E0507] Error:\u001b[0m cannot move out of index of `Vec<String>`",
|
||
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_6:1:1 \u001b[38;5;246m]\u001b[0m",
|
||
" \u001b[38;5;246m│\u001b[0m",
|
||
" \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mw\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54m[\u001b[0m\u001b[38;5;54m0\u001b[0m\u001b[38;5;54m]\u001b[0m\u001b[38;5;249m;\u001b[0m",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;68m│\u001b[0m ",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m help: consider borrowing here: `&`",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m│\u001b[0m \u001b[38;5;68m│\u001b[0m ",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m move occurs because value has type `String`, which does not implement the `Copy` trait",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m│\u001b[0m ",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider cloning the value if the performance cost is acceptable: `.clone()`",
|
||
"\u001b[38;5;246m───╯\u001b[0m"
|
||
]
|
||
},
|
||
{
|
||
"ename": "Error",
|
||
"evalue": "cannot move out of index of `Vec<String>`",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[31m[E0507] Error:\u001b[0m cannot move out of index of `Vec<String>`",
|
||
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_6:1:1 \u001b[38;5;246m]\u001b[0m",
|
||
" \u001b[38;5;246m│\u001b[0m",
|
||
" \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mw\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54m[\u001b[0m\u001b[38;5;54m1\u001b[0m\u001b[38;5;54m]\u001b[0m\u001b[38;5;249m;\u001b[0m",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;68m│\u001b[0m ",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m help: consider borrowing here: `&`",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m│\u001b[0m \u001b[38;5;68m│\u001b[0m ",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m move occurs because value has type `String`, which does not implement the `Copy` trait",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m│\u001b[0m ",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider cloning the value if the performance cost is acceptable: `.clone()`",
|
||
"\u001b[38;5;246m───╯\u001b[0m"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let mut words = vec![\"hello\".to_string(), \"world\".to_string(), \"!!!\".to_string()];\n",
|
||
"\n",
|
||
"let first_word = words[0];\n",
|
||
"let second_word = words[1];"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* We can move (consume) items of a vector in a loop:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"[\"hello\", \"world\", \"!!!\"]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let mut target_words: Vec<String> = Vec::new();\n",
|
||
"\n",
|
||
"let mut words = vec![\"hello\".to_string(), \"world\".to_string(), \"!!!\".to_string()];\n",
|
||
"\n",
|
||
"for word in words {\n",
|
||
" target_words.push(word);\n",
|
||
"}\n",
|
||
"\n",
|
||
"println!(\"{:?}\", target_words);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Ownership and functions\n",
|
||
"\n",
|
||
"* The mechanics of passing a value to a function are similar to those when assigning a value to a variable\n",
|
||
"* Passing a variable to a function will move or copy, just as assignment does"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"number = 3.14159\n",
|
||
"pi = 3.14159\n",
|
||
"text = TEXT\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"fn takes_ownership(text: String) {\n",
|
||
" println!(\"text = {text}\");\n",
|
||
"} \n",
|
||
"\n",
|
||
"fn takes_copy(number: f64) {\n",
|
||
" println!(\"number = {number}\");\n",
|
||
"}\n",
|
||
"\n",
|
||
"fn main() {\n",
|
||
" let pi = 3.14159;\n",
|
||
" takes_copy(pi);\n",
|
||
" println!(\"pi = {pi}\");\n",
|
||
"\n",
|
||
" let text = String::from(\"TEXT\");\n",
|
||
" takes_ownership(text);\n",
|
||
" // println!(\"text = {text}\"); // comment-out this line\n",
|
||
"}\n",
|
||
"\n",
|
||
"main();"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Return Values and Scope\n",
|
||
"\n",
|
||
"* Returning values can also transfer ownership"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 17,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Ownership!!!\n",
|
||
"Ownership!!!\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"fn gives_ownership() -> String {\n",
|
||
" let text = String::from(\"Ownership!!!\");\n",
|
||
"\n",
|
||
" text\n",
|
||
"}\n",
|
||
"\n",
|
||
"fn transfers_ownership(text: String) -> String {\n",
|
||
" text\n",
|
||
"}\n",
|
||
"\n",
|
||
"fn main() {\n",
|
||
" let txt1 = gives_ownership();\n",
|
||
" let txt2 = transfers_ownership(txt1);\n",
|
||
" // println!(\"{txt1}\"); // comment-out this line\n",
|
||
" println!(\"{txt2}\");\n",
|
||
"\n",
|
||
" println!(\"{}\", transfers_ownership(gives_ownership())); \n",
|
||
"}\n",
|
||
"\n",
|
||
"main();"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# References & Borrowing\n",
|
||
"\n",
|
||
"* A reference lets you access a value without affecting its ownership. References come in two kinds:\n",
|
||
" * A **shared reference** lets you read but not modify its referent. However, you can have as many shared references to a particular value at a time as you like. The expression `&e` yields a shared reference to `e`’s value; if `e` has the type `T`, then `&e` has the type `&T`, pronounced “ref T”. Shared references are `Copy`\n",
|
||
" * If you have a **mutable reference** to a value, you may both read and modify the value. However, you may not have any other references of any sort to that value active at the same time. The expression `&mut e` yields a mutable reference to `e`’s value; you write its type as `&mut T`, which is pronounced “ref mute T”. Mutable references are not `Copy`."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* In Rust, references are created explicitly with the `&` operator, and dereferenced explicitly with the `*` operator:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"()"
|
||
]
|
||
},
|
||
"execution_count": 3,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"{\n",
|
||
" let x = 10;\n",
|
||
" let rx = &x; // &x is a shared reference to x\n",
|
||
" \n",
|
||
" assert!(*rx == 10); // explcitly dereference rx\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* To create a mutable reference, use the `&mut` operator:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"()"
|
||
]
|
||
},
|
||
"execution_count": 5,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"{\n",
|
||
" let mut y = 42;\n",
|
||
" let ry = &mut y; // &mut y is a mutable reference to y\n",
|
||
" *ry += 10;\n",
|
||
" \n",
|
||
" assert!(y == 52);\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Assigning References"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Assigning to a Rust reference makes it point at a new value:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 24,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"()"
|
||
]
|
||
},
|
||
"execution_count": 24,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"{\n",
|
||
" let flag = true;\n",
|
||
"\n",
|
||
" let x = 10;\n",
|
||
" let y = 20;\n",
|
||
" let mut r: &i32 = &x;\n",
|
||
"\n",
|
||
" if flag { r = &y; }\n",
|
||
"\n",
|
||
" assert!(*r == 10 || *r == 20);\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### References to References\n",
|
||
"\n",
|
||
"* Rust permits references to references.\n",
|
||
"* Explicit dereferencing requires as many `*` as levels of indirections\n",
|
||
"* The `.` operator follows as many references as it takes to find its target."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 25,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"struct Point { x: i32, y: i32 }\n",
|
||
"\n",
|
||
"fn ref_to_ref() {\n",
|
||
" let point = Point { x: 1000, y: 729 };\n",
|
||
"\n",
|
||
" let ry: &i32 = &point.y;\n",
|
||
" let rry: &&i32 = &ry;\n",
|
||
" let rrry: &&&i32 = &rry;\n",
|
||
" assert!(***rrry == 729);\n",
|
||
"\n",
|
||
" let r: &Point = &point;\n",
|
||
" let rr: &&Point = &r;\n",
|
||
" let rrr: &&&Point = &rr;\n",
|
||
" assert!(rrr.y == 729);\n",
|
||
"}\n",
|
||
"\n",
|
||
"ref_to_ref();"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Comparing References\n",
|
||
"\n",
|
||
"* Like the `.` operator, Rust’s comparison operators “see through” any number of references, as long as both operands have the same type.\n",
|
||
"* If you actually want to know whether two references point to the same memory, you can use `std::ptr::eq`, which compares them as addresses:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 22,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"()"
|
||
]
|
||
},
|
||
"execution_count": 22,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"{\n",
|
||
" let x = 10;\n",
|
||
" let y = 10;\n",
|
||
"\n",
|
||
" let rx = &x;\n",
|
||
" let ry = &y;\n",
|
||
"\n",
|
||
" assert!(rx == ry); // their referents are equal\n",
|
||
" assert!(!std::ptr::eq(rx, ry)); // but occupy different addresses\n",
|
||
" \n",
|
||
" let rrx = ℞\n",
|
||
" let rry = &ry;\n",
|
||
"\n",
|
||
" assert!(**rrx <= **rry); // explicit dereferencing using **\n",
|
||
" assert!(rrx == rry); // implicit dereferencing using **\n",
|
||
" assert!(rrx <= rry);\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### References Are Never Null\n",
|
||
"* Rust references are never null. \n",
|
||
" * there’s no analogue to C’s `NULL` or C++’s `nullptr`\n",
|
||
" * and Rust won’t convert integers to references (outside of unsafe code), so you can’t convert zero into a reference."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Borrowing References to Arbitrary Expressions\n",
|
||
"\n",
|
||
"* Rust lets you borrow a reference (apply `&`) to the value of any sort of expression:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 28,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"fn factorial(n: usize) -> usize {\n",
|
||
" (1..n+1).fold(1, |a, b| a * b)\n",
|
||
"}\n",
|
||
"\n",
|
||
"fn main() {\n",
|
||
" let r = &factorial(6);\n",
|
||
"\n",
|
||
" // Arithmetic operators can see through one level of references.\n",
|
||
" assert_eq!(r + &1009, 1729);\n",
|
||
"}\n",
|
||
"\n",
|
||
"main();"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Rust simply creates an anonymous variable to hold the expression’s value, and makes the reference point to that. The lifetime of this anonymous variable depends on what you do with the reference:\n",
|
||
"\n",
|
||
" * if you immediately assign the reference to a variable in a `let` statement (or make it part of some struct or array that is being immediately assigned), then Rust makes the anonymous variable live as long as the variable the `let` initializes. In the preceding example, Rust would do this for the referent of `r`.\n",
|
||
" * Otherwise, the anonymous variable lives to the end of the enclosing statement. In our example, the anonymous variable created to hold `1009` lasts only to the end of the `assert_eq!` statement."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Reference safety\n",
|
||
"\n",
|
||
"### Borrowing a Local \n",
|
||
"\n",
|
||
"* You can’t borrow a reference to a local variable and take it out of the variable’s scope:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 29,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"ename": "Error",
|
||
"evalue": "`x` does not live long enough",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[31m[E0597] Error:\u001b[0m `x` does not live long enough",
|
||
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_29:1:1 \u001b[38;5;246m]\u001b[0m",
|
||
" \u001b[38;5;246m│\u001b[0m",
|
||
" \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m4\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m;\u001b[0m",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m┬\u001b[0m ",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m binding `x` declared here",
|
||
" \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;54mx\u001b[0m\u001b[38;5;249m;\u001b[0m",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m ",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m borrowed value does not live long enough",
|
||
" \u001b[38;5;246m7 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m}\u001b[0m",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m┬\u001b[0m ",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m `x` dropped here while still borrowed",
|
||
" \u001b[38;5;240m │\u001b[0m ",
|
||
" \u001b[38;5;246m9 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;37m*\u001b[0m\u001b[38;5;37mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;37m─\u001b[0m\u001b[38;5;37m┬\u001b[0m ",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m borrow later used here",
|
||
"\u001b[38;5;246m───╯\u001b[0m"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"{\n",
|
||
" let r;\n",
|
||
"\n",
|
||
" {\n",
|
||
" let x = 42;\n",
|
||
" r = &x;\n",
|
||
" }\n",
|
||
"\n",
|
||
" assert!(*r == 1);\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Receiving References as Parameters"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Static variables\n",
|
||
"\n",
|
||
"* Rust’s equivalent of a global variable is called a **static**\n",
|
||
"* It’s a value that’s created when the program starts and lasts until it terminates\n",
|
||
"* Every static must be initialized\n",
|
||
"* **Mutable statics** are inherently not thread-safe (after all, any thread can access a static at any time), and even in single-threaded programs, they can fall prey to other sorts of reentrancy problems. For these reasons, you may access a mutable static only within an `unsafe` block.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Assignment to static reference\n",
|
||
"\n",
|
||
"* Static references can only refer to other statics - this avoids dangling reference\n",
|
||
"* In the code below variable `p` has some lifetime (but it is not a static) `=>` Rust rejects this code - assignment `p` to `STASH` could lead to dangling reference "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"ename": "Error",
|
||
"evalue": "lifetime may not live long enough",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[31mError:\u001b[0m lifetime may not live long enough",
|
||
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_9:1:1\u001b[38;5;246m]\u001b[0m",
|
||
" \u001b[38;5;246m│\u001b[0m",
|
||
" \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
|
||
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m┬\u001b[0m ",
|
||
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m let's call the lifetime of this reference `'1`",
|
||
" \u001b[38;5;246m ·\u001b[0m ",
|
||
" \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mS\u001b[0m\u001b[38;5;100mT\u001b[0m\u001b[38;5;100mA\u001b[0m\u001b[38;5;100mS\u001b[0m\u001b[38;5;100mH\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100m=\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100mp\u001b[0m\u001b[38;5;249m;\u001b[0m",
|
||
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m ",
|
||
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m assignment requires that `'1` must outlive `'static`",
|
||
"\u001b[38;5;246m───╯\u001b[0m"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"static mut STASH: &i32 = &128;\n",
|
||
"\n",
|
||
"fn put_on_stash(p: &i32) {\n",
|
||
" unsafe {\n",
|
||
" STASH = p;\n",
|
||
" }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* In order to compile `put_on_stash()` function we have annotate that `p` is a reference to static data"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"static mut STASH: &i32 = &10;\n",
|
||
"\n",
|
||
"fn put_on_stash(p: &'static i32) {\n",
|
||
" unsafe {\n",
|
||
" STASH = p;\n",
|
||
" }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"665"
|
||
]
|
||
},
|
||
"execution_count": 11,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"static SOME_DATA: i32 = 665;\n",
|
||
"\n",
|
||
"put_on_stash(&SOME_DATA);\n",
|
||
"\n",
|
||
"unsafe { *STASH }"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Returning references"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Functions can return references\n",
|
||
"* Dangling references are reported at compile time"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"fn smallest(v: &[i32]) -> &i32 {\n",
|
||
" let mut smallest_value: &i32 = &v[0];\n",
|
||
"\n",
|
||
" for value in &v[1..] {\n",
|
||
" if *value < *smallest_value {\n",
|
||
" smallest_value = value;\n",
|
||
" } \n",
|
||
" }\n",
|
||
" smallest_value\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 30,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"ename": "Error",
|
||
"evalue": "cannot find function `smallest` in this scope",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[31m[E0425] Error:\u001b[0m cannot find function `smallest` in this scope",
|
||
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_30:1:1 \u001b[38;5;246m]\u001b[0m",
|
||
" \u001b[38;5;246m│\u001b[0m",
|
||
" \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249m)\u001b[0m",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
|
||
"\u001b[38;5;246m───╯\u001b[0m"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let v;\n",
|
||
"{\n",
|
||
" let data = [5, 345, 1, 4, 42, 665];\n",
|
||
" v = smallest(&data)\n",
|
||
"}\n",
|
||
"assert!(*v == 1);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Correct version of the snippet above"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 31,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"ename": "Error",
|
||
"evalue": "cannot find function `smallest` in this scope",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[31m[E0425] Error:\u001b[0m cannot find function `smallest` in this scope",
|
||
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_31:1:1 \u001b[38;5;246m]\u001b[0m",
|
||
" \u001b[38;5;246m│\u001b[0m",
|
||
" \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
|
||
"\u001b[38;5;246m───╯\u001b[0m"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"{\n",
|
||
" let data = [5, 345, 1, 4, 42, 665];\n",
|
||
" let v = smallest(&data);\n",
|
||
" assert!(*v == 1);\n",
|
||
"}"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Rust",
|
||
"language": "rust",
|
||
"name": "rust"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": "rust",
|
||
"file_extension": ".rs",
|
||
"mimetype": "text/rust",
|
||
"name": "rust",
|
||
"pygment_lexer": "rust",
|
||
"version": ""
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 2
|
||
}
|