718 lines
31 KiB
Text
718 lines
31 KiB
Text
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Functions & Closures"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"People ordered by age: [Person { name: \"Marry\", age: 11, height: 1.5 }, Person { name: \"Adam\", age: 16, height: 1.6 }, Person { name: \"Alice\", age: 20, height: 1.7 }, Person { name: \"Bob\", age: 25, height: 1.8 }, Person { name: \"Charlie\", age: 30, height: 1.9 }, Person { name: \"David\", age: 35, height: 1.75 }, Person { name: \"Eve\", age: 40, height: 1.75 }]\n",
|
||
"People ordered by height: [Person { name: \"Marry\", age: 11, height: 1.5 }, Person { name: \"Adam\", age: 16, height: 1.6 }, Person { name: \"Alice\", age: 20, height: 1.7 }, Person { name: \"David\", age: 35, height: 1.75 }, Person { name: \"Eve\", age: 40, height: 1.75 }, Person { name: \"Bob\", age: 25, height: 1.8 }, Person { name: \"Charlie\", age: 30, height: 1.9 }]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"#[derive(Debug, PartialEq, Clone)]\n",
|
||
"struct Person {\n",
|
||
" name: String,\n",
|
||
" age: u8,\n",
|
||
" height: f32\n",
|
||
"}\n",
|
||
"\n",
|
||
"fn create_people() -> Vec<Person> {\n",
|
||
" vec![\n",
|
||
" Person {\n",
|
||
" name: \"Alice\".to_string(),\n",
|
||
" age: 20,\n",
|
||
" height: 1.7\n",
|
||
" },\n",
|
||
" Person {\n",
|
||
" name: \"Bob\".to_string(),\n",
|
||
" age: 25,\n",
|
||
" height: 1.8\n",
|
||
" },\n",
|
||
" Person {\n",
|
||
" name: \"Charlie\".to_string(),\n",
|
||
" age: 30,\n",
|
||
" height: 1.9\n",
|
||
" },\n",
|
||
" Person {\n",
|
||
" name: \"David\".to_string(),\n",
|
||
" age: 35,\n",
|
||
" height: 1.75\n",
|
||
" },\n",
|
||
" Person {\n",
|
||
" name: \"Eve\".to_string(),\n",
|
||
" age: 40,\n",
|
||
" height: 1.75\n",
|
||
" },\n",
|
||
" Person {\n",
|
||
" name: \"Adam\".to_string(),\n",
|
||
" age: 16,\n",
|
||
" height: 1.6\n",
|
||
" },\n",
|
||
" Person {\n",
|
||
" name: \"Marry\".to_string(),\n",
|
||
" age: 11,\n",
|
||
" height: 1.5\n",
|
||
" }\n",
|
||
" ]\n",
|
||
"}\n",
|
||
"\n",
|
||
"let people = create_people();\n",
|
||
"\n",
|
||
"let people_sorted_by_age = {\n",
|
||
" let mut people = people.clone();\n",
|
||
" people.sort_by_key(|person| person.age);\n",
|
||
" people\n",
|
||
"};\n",
|
||
"\n",
|
||
"let people_sorted_by_height = {\n",
|
||
" let mut people = people.clone();\n",
|
||
" people.sort_by(|person, other| f32::total_cmp(&person.height, &other.height));\n",
|
||
" people\n",
|
||
"};\n",
|
||
"\n",
|
||
"println!(\"People ordered by age: {:?}\", people_sorted_by_age);\n",
|
||
"println!(\"People ordered by height: {:?}\", people_sorted_by_height);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Closures Borrow by Default"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"People with translated names: [Person { name: \"Alicja\", age: 20, height: 1.7 }, Person { name: \"Robert\", age: 25, height: 1.8 }, Person { name: \"Karol\", age: 30, height: 1.9 }, Person { name: \"Dawid\", age: 35, height: 1.75 }, Person { name: \"Ewa\", age: 40, height: 1.75 }, Person { name: \"Adam\", age: 16, height: 1.6 }, Person { name: \"Maria\", age: 11, height: 1.5 }]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"use std::collections::HashMap;\n",
|
||
"\n",
|
||
"fn create_name_translator() -> HashMap<String, String> {\n",
|
||
" [\n",
|
||
" (\"Alice\".to_string(), \"Alicja\".to_string()),\n",
|
||
" (\"Bob\".to_string(), \"Robert\".to_string()),\n",
|
||
" (\"Charlie\".to_string(), \"Karol\".to_string()),\n",
|
||
" (\"David\".to_string(), \"Dawid\".to_string()),\n",
|
||
" (\"Eve\".to_string(), \"Ewa\".to_string()),\n",
|
||
" (\"Adam\".to_string(), \"Adam\".to_string()),\n",
|
||
" (\"Marry\".to_string(), \"Maria\".to_string())\n",
|
||
" ].iter().cloned().collect()\n",
|
||
"}\n",
|
||
"\n",
|
||
"fn main() {\n",
|
||
" let people = create_people();\n",
|
||
"\n",
|
||
" let name_translator: HashMap<_, _> = create_name_translator();\n",
|
||
"\n",
|
||
" let person_name_translator = |person: &Person| {\n",
|
||
" let translated_name = name_translator.get(&person.name).unwrap_or(&person.name); // name_translator is borrowed\n",
|
||
" Person {\n",
|
||
" name: translated_name.to_string(),\n",
|
||
" age: person.age,\n",
|
||
" height: person.height\n",
|
||
" }\n",
|
||
" };\n",
|
||
"\n",
|
||
" let people_translated: Vec<Person> = people.iter().map(person_name_translator).collect();\n",
|
||
"\n",
|
||
" println!(\"People with translated names: {:?}\", people_translated);\n",
|
||
"}\n",
|
||
"\n",
|
||
"main();"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Closures That Move"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"People with translated names: [Person { name: \"Alicja\", age: 20, height: 1.7 }, Person { name: \"Robert\", age: 25, height: 1.8 }, Person { name: \"Karol\", age: 30, height: 1.9 }, Person { name: \"Dawid\", age: 35, height: 1.75 }, Person { name: \"Ewa\", age: 40, height: 1.75 }, Person { name: \"Adam\", age: 16, height: 1.6 }, Person { name: \"Maria\", age: 11, height: 1.5 }]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"fn main() {\n",
|
||
" let people: Vec<Person> = create_people();\n",
|
||
" let name_translator: HashMap<String, String> = create_name_translator();\n",
|
||
"\n",
|
||
" let person_name_translator = move |person: &Person| {\n",
|
||
" let translated_name = name_translator.get(&person.name).unwrap_or(&person.name); // name_translator is moved\n",
|
||
" Person {\n",
|
||
" name: translated_name.to_string(),\n",
|
||
" age: person.age,\n",
|
||
" height: person.height\n",
|
||
" }\n",
|
||
" };\n",
|
||
"\n",
|
||
" let thd = std::thread::spawn(move || { \n",
|
||
" let people_translated: Vec<Person> = people.iter().map(person_name_translator).collect(); // people & person_name_translator are moved\n",
|
||
" \n",
|
||
" println!(\"People with translated names: {:?}\", people_translated);\n",
|
||
" });\n",
|
||
"\n",
|
||
" thd.join().unwrap();\n",
|
||
"}\n",
|
||
"\n",
|
||
"main();"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Function & Closure Types"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Function Type"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"fn is_adult(person: &Person) -> bool {\n",
|
||
" person.age >= 18\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"The function `is_adult` has a type: `fn(&Person) -> bool`"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Adults: [Person { name: \"Alice\", age: 20, height: 1.7 }, Person { name: \"Bob\", age: 25, height: 1.8 }, Person { name: \"Charlie\", age: 30, height: 1.9 }, Person { name: \"David\", age: 35, height: 1.75 }, Person { name: \"Eve\", age: 40, height: 1.75 }]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let f_predicate: fn(&Person) -> bool = is_adult;\n",
|
||
"\n",
|
||
"fn filter_by_predicate(people: &Vec<Person>, predicate: fn(&Person) -> bool) -> Vec<Person> {\n",
|
||
" let mut qualified: Vec<Person> = Vec::new();\n",
|
||
" for person in people {\n",
|
||
" if predicate(person) {\n",
|
||
" qualified.push(person.clone());\n",
|
||
" }\n",
|
||
" }\n",
|
||
" qualified\n",
|
||
"}\n",
|
||
"\n",
|
||
"let adults = filter_by_predicate(&people, is_adult);\n",
|
||
"\n",
|
||
"println!(\"Adults: {:?}\", adults);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"When function expects a function as an argument, it accepts a closure that captures nothing:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Tall people: [Person { name: \"Bob\", age: 25, height: 1.8 }, Person { name: \"Charlie\", age: 30, height: 1.9 }]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let tall_people = filter_by_predicate(&people, |person| person.height > 1.75);\n",
|
||
"\n",
|
||
"println!(\"Tall people: {:?}\", tall_people);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"A closure that captures variables from the enclosing scope cannot be passed to a function that accepts a function type:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"ename": "Error",
|
||
"evalue": "mismatched types",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[31m[E0308] Error:\u001b[0m mismatched types",
|
||
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_10:1:1 \u001b[38;5;246m]\u001b[0m",
|
||
" \u001b[38;5;246m│\u001b[0m",
|
||
" \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;249mt\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mf\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100ml\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100m_\u001b[0m\u001b[38;5;100mb\u001b[0m\u001b[38;5;100my\u001b[0m\u001b[38;5;100m_\u001b[0m\u001b[38;5;100mp\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100md\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100mc\u001b[0m\u001b[38;5;100ma\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m|\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54m|\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54m.\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m>\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;68mh\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mg\u001b[0m\u001b[38;5;68mh\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68m_\u001b[0m\u001b[38;5;68ml\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mm\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\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\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;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;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;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;54m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\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\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\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\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\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\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 arguments to this function are incorrect",
|
||
" \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\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;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 expected fn pointer, found closure",
|
||
" \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\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m `height_limit` captured here",
|
||
"\u001b[38;5;246m───╯\u001b[0m"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let height_limit = 1.75;\n",
|
||
"let tall_people = filter_by_predicate(&people, |person| person.height > height_limit);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### `Fn` Trait"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Functions and closures implement the `Fn` trait, which is the trait of things that can be called like functions."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"fn filter_by_predicate<F>(people: &Vec<Person>, predicate: F) -> Vec<Person>\n",
|
||
" where F: Fn(&Person) -> bool \n",
|
||
"{\n",
|
||
" let mut qualified: Vec<Person> = Vec::new();\n",
|
||
" for person in people {\n",
|
||
" if predicate(person) {\n",
|
||
" qualified.push(person.clone());\n",
|
||
" }\n",
|
||
" }\n",
|
||
" qualified\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 12,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Adults: [Person { name: \"Alice\", age: 20, height: 1.7 }, Person { name: \"Bob\", age: 25, height: 1.8 }, Person { name: \"Charlie\", age: 30, height: 1.9 }, Person { name: \"David\", age: 35, height: 1.75 }, Person { name: \"Eve\", age: 40, height: 1.75 }]\n",
|
||
"Tall people: [Person { name: \"Bob\", age: 25, height: 1.8 }, Person { name: \"Charlie\", age: 30, height: 1.9 }]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let adults = filter_by_predicate(&people, is_adult); // using function pointer\n",
|
||
"println!(\"Adults: {:?}\", adults);\n",
|
||
"\n",
|
||
"let height_limit = 1.75;\n",
|
||
"let tall_people = filter_by_predicate(&people, |person| person.height > height_limit); // using closure that captures (borrows) height_limit\n",
|
||
"println!(\"Tall people: {:?}\", tall_people);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Now the function `filter_by_predicate` is generic. It accepts any function or closure `F` that implements the special trait `Fn(&Person) -> bool`.\n",
|
||
"* The trait `Fn(&Person) -> bool` automatically implemented by all functions and closures that can be called with a `&Person` argument and return a `bool`."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### `FnMut` Trait\n",
|
||
"\n",
|
||
"* The `FnMut` trait is a subtrait of `Fn`. It allows the closure to mutate the captured variables."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 13,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Generated number: 11\n",
|
||
"Generated number: 12\n",
|
||
"Generated number: 13\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"fn create_generator(seed: i32) -> impl FnMut() -> i32 {\n",
|
||
" let mut state = seed;\n",
|
||
" move || {\n",
|
||
" state += 1; // mutating captured state\n",
|
||
" state\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"fn main() {\n",
|
||
" let mut generator = create_generator(10);\n",
|
||
" println!(\"Generated number: {}\", generator());\n",
|
||
" println!(\"Generated number: {}\", generator());\n",
|
||
" println!(\"Generated number: {}\", generator());\n",
|
||
"}\n",
|
||
"\n",
|
||
"main();"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"fn main() {\n",
|
||
" let mut state = 10;\n",
|
||
"\n",
|
||
" let mut f = || {\n",
|
||
" state += 1; // mutating captured state\n",
|
||
" state\n",
|
||
" };\n",
|
||
"\n",
|
||
" let mut boxed_f: Box<dyn FnMut()->i32> = Box::new(f);\n",
|
||
"\n",
|
||
" boxed_f();\n",
|
||
" boxed_f();\n",
|
||
"}\n",
|
||
"\n",
|
||
"main();"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": []
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### `FnOnce` Trait\n",
|
||
"\n",
|
||
"* Some functions and closures can be called only once. They are not allowed to be called multiple times.\n",
|
||
"* The trait `FnOnce` is the trait of things that can be called once. It is implemented by functions and closures that can be called only once.\n",
|
||
" * The `FnOnce` trait is a subtrait of the `FnMut` trait, which is a subtrait of the `Fn` trait."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"ename": "Error",
|
||
"evalue": "use of moved value: `f`",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[31m[E0382] Error:\u001b[0m use of moved value: `f`",
|
||
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_15: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;249mf\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;249md\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;68mm\u001b[0m\u001b[38;5;68my\u001b[0m\u001b[38;5;68m_\u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68mr\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68mg\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;249mt\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249me\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\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\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\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m note: closure cannot be invoked more than once because it moves the variable `my_string` out of its environment",
|
||
" \u001b[38;5;240m │\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;37mf\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;37m┬\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\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\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m note: this value implements `FnOnce`, which causes it to be moved when called",
|
||
" \u001b[38;5;240m │\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 `f` moved due to this call",
|
||
" \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;100mf\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\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 value used here after move",
|
||
"\u001b[38;5;246m───╯\u001b[0m"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"fn main() {\n",
|
||
" let my_string = \"Hello, World!\".to_string();\n",
|
||
" let f = || drop(my_string); // this closure should be called only once\n",
|
||
"\n",
|
||
" f();\n",
|
||
" f();\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 16,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Data: [1, 2, 3, 4, 5, 665]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"fn main() {\n",
|
||
" let mut data = vec![1, 2, 3, 4, 5];\n",
|
||
"\n",
|
||
" let mut f_once = || {\n",
|
||
" data.push(665); // mutating captured data\n",
|
||
" data // moving the data out of the closure\n",
|
||
" };\n",
|
||
"\n",
|
||
" let mut f_once_boxed: Box<dyn FnOnce() -> Vec<i32>> = Box::new(f_once);\n",
|
||
"\n",
|
||
" let data = f_once_boxed();\n",
|
||
" println!(\"Data: {:?}\", data);\n",
|
||
"}\n",
|
||
"\n",
|
||
"main();"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* `Fn` is the family of closures and functions that you can call multiple times without restriction. This highest category also includes all fn functions.\n",
|
||
"\n",
|
||
"* `FnMut` is the family of closures that can be called multiple times if the closure itself is declared mut.\n",
|
||
"\n",
|
||
"* `FnOnce` is the family of closures that can be called once, if the caller owns the closure.\n",
|
||
"\n",
|
||
"* Every `Fn` meets the requirements for `FnMut`, and every `FnMut` meets the requirements for `FnOnce`"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 61,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"// mod explain {\n",
|
||
"// // Pseudocode for `Fn`, `FnMut`, and `FnOnce` traits.\n",
|
||
"// trait Fn() -> R {\n",
|
||
"// fn call(&self) -> R;\n",
|
||
"// }\n",
|
||
"\n",
|
||
"// trait FnMut() -> R {\n",
|
||
"// fn call_mut(&mut self) -> R;\n",
|
||
"// }\n",
|
||
"\n",
|
||
"// trait FnOnce() -> R {\n",
|
||
"// fn call_once(self) -> R;\n",
|
||
"// }\n",
|
||
"// }"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Copy and Clone for Closures\n",
|
||
"\n",
|
||
"* Just as Rust automatically figures out which closures can be called only once, it can figure out which closures can implement `Copy` and `Clone`, and which cannot."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 17,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"fn main() {\n",
|
||
" let y = 4;\n",
|
||
" let add_y = move |x| x + y;\n",
|
||
" let copy_of_add_y = add_y; // closure is copied\n",
|
||
" assert_eq!(add_y(copy_of_add_y(3)), 11);\n",
|
||
"\n",
|
||
" let word: String = \"Hello\".to_string();\n",
|
||
" let append_word = move |mut s: String| {\n",
|
||
" s.push_str(&word); \n",
|
||
" s\n",
|
||
" };\n",
|
||
" let copy_of_append_word = append_word.clone(); // closure is cloned\n",
|
||
" assert_eq!(append_word(copy_of_append_word(\" World\".to_string())), \" WorldHelloHello\");\n",
|
||
"}\n",
|
||
"\n",
|
||
"main();"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Callbacks"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "rust"
|
||
}
|
||
},
|
||
"source": [
|
||
"* Callbacks are functions that are passed as arguments to other functions.\n",
|
||
"* Callbacks are used to implement event handlers, asynchronous programming, and other patterns."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 18,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"type Callback = Box<dyn Fn(f32)>;\n",
|
||
"\n",
|
||
"struct TemperaturMonitor {\n",
|
||
" current_temp: f32,\n",
|
||
" on_temperature_changed: Option<Callback>,\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 19,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"impl TemperaturMonitor {\n",
|
||
" fn new() -> Self {\n",
|
||
" Self {\n",
|
||
" current_temp: 0.0,\n",
|
||
" on_temperature_changed: None,\n",
|
||
" }\n",
|
||
" }\n",
|
||
"\n",
|
||
" fn set_on_temperature_changed<F: Fn(f32) + 'static>(&mut self, callback: F) {\n",
|
||
" self.on_temperature_changed = Some(Box::new(callback));\n",
|
||
" }\n",
|
||
"\n",
|
||
" fn set_current_temp(&mut self, temp: f32) {\n",
|
||
" self.current_temp = temp;\n",
|
||
" if let Some(ref on_temperature_changed) = self.on_temperature_changed {\n",
|
||
" on_temperature_changed(self.current_temp);\n",
|
||
" }\n",
|
||
" } \n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Rust makes us add this `'static bound`. Without it, the call to `Box::new(callback)` would be an error, because it’s not safe to store a closure if it contains borrowed references to variables that are about to go out of scope.)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 20,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Temperature changed to: 22.5\n",
|
||
"Temperature changed to: 23.5\n",
|
||
"Current temperature is: 24.7°C\n",
|
||
"Current temperature is: 27.1°C\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"fn main() {\n",
|
||
" let mut monitor = TemperaturMonitor::new();\n",
|
||
" monitor.set_on_temperature_changed(|temp| println!(\"Temperature changed to: {}\", temp));\n",
|
||
" monitor.set_current_temp(22.5);\n",
|
||
" monitor.set_current_temp(23.5);\n",
|
||
"\n",
|
||
" monitor.set_on_temperature_changed(|temp| println!(\"Current temperature is: {}°C\", temp));\n",
|
||
" monitor.set_current_temp(24.7);\n",
|
||
" monitor.set_current_temp(27.1);\n",
|
||
"}\n",
|
||
"\n",
|
||
"main();"
|
||
]
|
||
}
|
||
],
|
||
"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
|
||
}
|