Rust functions: Difference between revisions
From wikinotes
(19 intermediate revisions by the same user not shown) | |||
Line 51: | Line 51: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Note that rust supports unpacking multiple variables. | |||
<syntaxhighlight lang="rust"> | <syntaxhighlight lang="rust"> | ||
fn foo() -> (i32, String) { | fn foo() -> (i32, String) { | ||
Line 58: | Line 58: | ||
let (mynum, mystr) = foo(); | let (mynum, mystr) = foo(); | ||
</syntaxhighlight> | |||
Returning Traits, and <code>dyn</code> | |||
<syntaxhighlight lang="rust"> | |||
// Rust needs to know how much space each return object requires. | |||
// You can't return a trait, different implementations will require different amounts of memory. | |||
// Where you would return a trait, instead return a `Box<T>` (pointer) | |||
fn foo() -> Box<dyn MyTrait> { | |||
if foo { | |||
Box::new(ImplA{}) | |||
} else { | |||
Box::new(ImplB{}) | |||
} | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
</blockquote><!-- Return Values --> | </blockquote><!-- Return Values --> | ||
Line 83: | Line 97: | ||
<syntaxhighlight lang="rust"> | <syntaxhighlight lang="rust"> | ||
fn do_thing<T>(val: T) { ... } | fn do_thing<T>(val: T) { ... } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
See more details in [[rust generics]]. | |||
</blockquote><!-- Generics --> | </blockquote><!-- Generics --> | ||
</blockquote><!-- Function Signatures --> | </blockquote><!-- Function Signatures --> | ||
= Closures = | |||
<blockquote> | |||
* closures support type inference | |||
* closures can refer to objects defined in their scope -- but be careful of ownership semantics | |||
== Syntax == | |||
<blockquote> | |||
<syntaxhighlight lang="rust"> | |||
// closure w/o params | |||
let say_hi = || println!("hi"); | |||
say_hi(); | |||
// closure w/ params | |||
let say_hi_to = |name| println!("hi {}", name) | |||
let say_hi_to = |name: &str| println!("hi {}", name) | |||
say_hi_to("alex"); | |||
// closure w/ return value | |||
let get_name = || -> String { String::from("vaderd") } | |||
// multiline closure | |||
let print_three_times = |x| { | |||
println!("{}", x); | |||
println!("{}", x); | |||
println!("{}", x); | |||
}; | |||
</syntaxhighlight> | |||
</blockquote><!-- Syntax --> | |||
== OuterScope Access/Ownership == | |||
<blockquote> | |||
You can access variables from the scope the closure was created in.<br> | |||
Closures can reference or take ownership of these variables. | |||
<syntaxhighlight lang="rust"> | |||
// immutable reference | |||
let list = vec![1, 2, 3]; | |||
let my_closure = || println!("{:?}", list); // immutable closure, immutable borrow | |||
my_closure(); | |||
// mutable reference | |||
let mut list = vec![1, 2, 3]; | |||
let mut my_closure = || list.push(4); // mutable closure, mutable borrow | |||
my_closure(); | |||
// assign take ownership (ex. move to thread) | |||
let list = vec![1, 2, 3]; | |||
let my_closure = move || println!(":?", list); // `move` means take ownership | |||
my_closure(); | |||
</syntaxhighlight> | |||
</blockquote><!-- Outer Scope Access/Ownership --> | |||
== Closure Traits == | |||
<blockquote> | |||
Closure traits determine | |||
* if repeated calls are allowed | |||
* it's scope-variable ownership semantics | |||
You can use them in method signatures, like other [[rust traits]]. | |||
* [https://doc.rust-lang.org/std/ops/trait.FnOnce.html FnOnce] all closures have this trait. unless another trait is applied, only callable once. | |||
* [https://doc.rust-lang.org/std/ops/trait.FnMut.html FnMut] mutable closures without <code>move</code>. supports multiple calls | |||
* [https://doc.rust-lang.org/std/ops/trait.Fn.html Fn] immutable closures without <code>move</code>. supports multiple calls | |||
</blockquote><!-- Closure Traits --> | |||
</blockquote><!-- Closures --> |
Latest revision as of 04:49, 11 February 2023
Expressions vs Statements
- statements include actions without a return value (ends in ;)
- expressions include actions with a return value (no ;)
statement
{ let y = 1; y += 1; } // no return valexpression
let x = { let y = 1; y += 1 // <-- no semicolon } // returns 2
Function Signatures
Params
fn main(num: u8) { println!("{}", num); }Return Values
// return void fn foo() { println!("hi"); } // single return value fn foo() -> i32 { 123 // <-- return value (no semicolon) } // multiple return values fn foo() -> (i32, String) { (123, String::from("abc")) }Note that rust supports unpacking multiple variables.
fn foo() -> (i32, String) { (123, String::from("abc")) } let (mynum, mystr) = foo();Returning Traits, and
dyn
// Rust needs to know how much space each return object requires. // You can't return a trait, different implementations will require different amounts of memory. // Where you would return a trait, instead return a `Box<T>` (pointer) fn foo() -> Box<dyn MyTrait> { if foo { Box::new(ImplA{}) } else { Box::new(ImplB{}) } }References
References let you pass an argument to a function without transferring ownership.
By default, references are not mutable, but themut
keyword makes it so.// pass reference to string fn len(s: &String) -> usize { s.len() } // if mutable, '&' placed before the keyword fn len(s: &mut str) -> usize { s.len() }Generics
fn do_thing<T>(val: T) { ... }See more details in rust generics.
Closures
- closures support type inference
- closures can refer to objects defined in their scope -- but be careful of ownership semantics
Syntax
// closure w/o params let say_hi = || println!("hi"); say_hi(); // closure w/ params let say_hi_to = |name| println!("hi {}", name) let say_hi_to = |name: &str| println!("hi {}", name) say_hi_to("alex"); // closure w/ return value let get_name = || -> String { String::from("vaderd") } // multiline closure let print_three_times = |x| { println!("{}", x); println!("{}", x); println!("{}", x); };OuterScope Access/Ownership
You can access variables from the scope the closure was created in.
Closures can reference or take ownership of these variables.// immutable reference let list = vec![1, 2, 3]; let my_closure = || println!("{:?}", list); // immutable closure, immutable borrow my_closure(); // mutable reference let mut list = vec![1, 2, 3]; let mut my_closure = || list.push(4); // mutable closure, mutable borrow my_closure(); // assign take ownership (ex. move to thread) let list = vec![1, 2, 3]; let my_closure = move || println!(":?", list); // `move` means take ownership my_closure();Closure Traits
Closure traits determine
- if repeated calls are allowed
- it's scope-variable ownership semantics
You can use them in method signatures, like other rust traits.