# Rust半小时教程

let

let x; // declare "x"
x = 42; // assign 42 to "x"


let x = 42;


let x: i32; // i32 is a signed 32-bit integer
x = 42;

// there's i8, i16, i32, i64, i128
// also u8, u16, u32, u64, u128 for unsigned


let x: i32 = 42;


let x;
foobar(x); // error: borrow of possibly-uninitialized variable: x
x = 42;


let x;
x = 42;
foobar(x); // the type of x will be inferred from here


// this does *nothing* because 42 is a constant
let _ = 42;

// this calls get_thing but throws away its result
let _ = get_thing();


// we may use _x eventually, but our code is a work-in-progress
// and we just wanted to get rid of a compiler warning for now.
let _x = 42;


let x = 13;
let x = x + 3;
// using x after that line only refers to the second x,
// the first x no longer exists.


Rust有 tuple类型
，你可以把它看作有固定长度的不同类型的集合:

let pair = ('a', 17);
pair.0; // this is 'a'
pair.1; // this is 17


let pair: (char, i32) = ('a', 17);


Tuple类型可以通过赋值方式进行解构(destructured)，这意味着它们被分成各自独立的字段:

let (some_char, some_int) = ('a', 17);
// now, some_char is 'a', and some_int is 17


let (left, right) = slice.split_at(middle);


let (_, right) = slice.split_at(middle);


let x = 3;
let y = 5;
let z = y + x;


let x = vec![1, 2, 3, 4, 5, 6, 7, 8]
.iter()
.map(|x| x + 3)
.fold(0, |x, y| x + y);


(之后我们再介绍这段代码的意义)

fn

fn greet() {
println!("Hi there!");
}


fn fair_dice_roll() -> i32 {
4
}


// This prints "in", then "out"
fn main() {
let x = "out";
{
// this is a different x
let x = "in";
println!(x);
}
println!(x);
}


// this:
let x = 42;

// is equivalent to this:
let x = { 42 };


let x = {
let y = 1; // first statement
let z = 2; // second statement
y + z // this is the *tail* - what the whole block will evaluate to
};


fn fair_dice_roll() -> i32 {
return 4;
}

fn fair_dice_roll() -> i32 {
4
}


if

fn fair_dice_roll() -> i32 {
if feeling_lucky {
6
} else {
4
}
}


match

fn fair_dice_roll() -> i32 {
match feeling_lucky {
true => 6,
false => 4,
}
}


)用来访问一个值的字段:

let a = (10, 20);
a.0; // this is 10

let amos = get_some_struct();
amos.nickname; // this is "fasterthanlime"


let nick = "fasterthanlime";
nick.len(); // this is 14


)类似点号但是操作的对象是命名空间。

， 源文件)， min

let least = std::cmp::min(3, 8); // this is 3


use

use std::cmp::min;

let least = min(7, 1); // this is 1


)。如果我们想同时引入 max
min
，我们可以这么做:

// this works:
use std::cmp::min;
use std::cmp::max;

// this also works:
use std::cmp::{min, max};

// this also works!
use std::{cmp::min, cmp::max};


// this brings min and max in scope, and many other things
use std::cmp::*;


let x = "amos".len(); // this is 4
let x = str::len("amos"); // this is also 4


str

// Vec is a regular struct, not a primitive type
let v = Vec::new();

// this is exactly the same code, but with the *full* path to Vec
let v = std::vec::Vec::new();


use std::prelude::v1::*;


String
Option
Result

struct Vec2 {
x: f64, // 64-bit floating point, aka "double precision"
y: f64,
}


let v1 = Vec2 { x: 1.0, y: 3.0 };
let v2 = Vec2 { y: 2.0, x: 4.0 };
// the order does not matter, only the names do


let v3 = Vec2 {
x: 14.0,
..v2
};


，只能发生在最后的位置，后面没有逗号。

let v4 = Vec2 { ..v3 };


let (left, right) = slice.split_at(middle);


let v = Vec2 { x: 3.0, y: 6.0 };
let Vec2 { x, y } = v;
// x is now 3.0, y is now 6.0


let Vec2 { x, .. } = v;
// this throws away v.y


let

struct Number {
odd: bool,
value: i32,
}

fn main() {
let one = Number { odd: true, value: 1 };
let two = Number { odd: false, value: 2 };
print_number(one);
print_number(two);
}

fn print_number(n: Number) {
if let Number { odd: true, value } = n {
println!("Odd number: {}", value);
} else if let Number { odd: false, value } = n {
println!("Even number: {}", value);
}
}

// this prints:
// Odd number: 1
// Even number: 2


match

:

fn print_number(n: Number) {
match n {
Number { odd: true, value } => println!("Odd number: {}", value),
Number { odd: false, value } => println!("Even number: {}", value),
}
}

// this prints the same as before


fn print_number(n: Number) {
match n {
Number { value: 1, .. } => println!("One"),
Number { value: 2, .. } => println!("Two"),
Number { value, .. } => println!("{}", value),
// if that last arm didn't exist, we would get a compile-time error
}
}


fn print_number(n: Number) {
match n.value {
1 => println!("One"),
2 => println!("Two"),
_ => println!("{}", n.value),
}
}


struct Number {
odd: bool,
value: i32,
}

impl Number {
fn is_strictly_positive(self) -> bool {
self.value > 0
}
}


fn main() {
let minus_two = Number {
odd: false,
value: -2,
};
println!("positive? {}", minus_two.is_strictly_positive());
// this prints "positive? false"
}


fn main() {
let n = Number {
odd: true,
value: 17,
};
n.odd = false; // error: cannot assign to n.odd,
// as n is not declared to be mutable
}


fn main() {
let n = Number {
odd: true,
value: 17,
};
n = Number {
odd: false,
value: 22,
}; // error: cannot assign twice to immutable variable n
}


mut

fn main() {
let mut n = Number {
odd: true,
value: 17,
}
n.value = 19; // all good
}


trait

trait Signed {
fn is_strictly_negative(self) -> bool;
}


• 为任意类型实现你自己定义的trait
• 为你的类型实现任意类型的trait
• 不允许为别人的类型实现别人的trait

(orphan rules)。

impl Signed for Number {
fn is_strictly_negative(self) -> bool {
self.value < 0
}
}

fn main() {
let n = Number { odd: false, value: -44 };
println!("{}", n.is_strictly_negative()); // prints "true"
}


impl Signed for i32 {
fn is_strictly_negative(self) -> bool {
self < 0
}
}

fn main() {
let n: i32 = -44;
println!("{}", n.is_strictly_negative()); // prints "true"
}


// the Neg trait is used to overload -, the
// unary minus operator.
impl std::ops::Neg for Number {
type Output = Number;

fn neg(self) -> Number {
Number {
value: -self.value,
odd: self.odd,
}
}
}

fn main() {
let n = Number { odd: true, value: 987 };
let m = -n; // this is only possible because we implemented Neg
println!("{}", m.value); // prints "-987"
}


impl

impl std::ops::Neg for Number {
type Output = Self;

fn neg(self) -> Self {
Self {
value: -self.value,
odd: self.odd,
}
}
}


)，它并不是指示类型要实现什么方法，而是说这种类型可以用作做特定的事情。

trait(简单地讲， i32

fn main() {
let a: i32 = 15;
let b = a; // a is copied
let c = a; // a is copied again
}


fn print_i32(x: i32) {
println!("x = {}", x);
}

fn main() {
let a: i32 = 15;
print_i32(a); // a is copied
print_i32(a); // a is copied again
}


,所以下面的代码不工作:

fn main() {
let n = Number { odd: true, value: 51 };
let m = n; // n is moved into m
let o = n; // error: use of moved value: n
}


fn print_number(n: Number) {
println!("{} number {}", if n.odd { "odd" } else { "even" }, n.value);
}

fn main() {
let n = Number { odd: true, value: 51 };
print_number(n); // n is moved
print_number(n); // error: use of moved value: n
}


fn print_number(n: &Number) {
println!("{} number {}", if n.odd { "odd" } else { "even" }, n.value);
}

fn main() {
let n = Number { odd: true, value: 51 };
print_number(&n); // n is borrowed for the time of the call
print_number(&n); // n is borrowed again
}


fn invert(n: &mut Number) {
n.value = -n.value;
}

fn print_number(n: &Number) {
println!("{} number {}", if n.odd { "odd" } else { "even" }, n.value);
}

fn main() {
// this time, n is mutable
let mut n = Number { odd: true, value: 51 };
print_number(&n);
invert(&mut n); // n is borrowed mutably - everything is explicit
print_number(&n);
}


Trait方法中的 self

impl std::clone::Clone for Number {
fn clone(&self) -> Self {
Self { ..*self }
}


fn main() {
let n = Number { odd: true, value: 51 };
let mut m = n.clone();
m.value += 100;

print_number(&n);
print_number(&m);
}


let m = n.clone();

let m = std::clone::Clone::clone(&n);


Copy

// note: Copy requires that Clone is implemented too
impl std::clone::Clone for Number {
fn clone(&self) -> Self {
Self { ..*self }
}
}

impl std::marker::Copy for Number {}


fn main() {
let n = Number { odd: true, value: 51 };
let m = n.clone();
let o = n.clone();
}


fn main() {
let n = Number { odd: true, value: 51 };
let m = n; // m is a copy of n
let o = n; // same. n is neither moved nor borrowed.
}


#[derive(Clone, Copy)]
struct Number {
odd: bool,
value: i32,
}

// this expands to impl Clone for Number and impl Copy for Number blocks.


fn foobar(arg: T) {
// do something with arg
}


fn foobar(left: L, right: R) {
// do something with left and right
}


fn print(value: T) {
println!("value = {}", value);
}

fn print(value: T) {
println!("value = {:?}", value);
}


fn print(value: T)
where
T: Display,
{
println!("value = {}", value);
}


use std::fmt::Debug;

fn compare(left: T, right: T)
where
T: Debug + PartialEq,
{
println!("{:?} {} {:?}", left, if left == right { "==" } else { "!=" }, right);
}

fn main() {
compare("tea", "coffee");
// prints: "tea" != "coffee"
}


module

fn main() {
use std::any::type_name;
println!("{}", type_name::()); // prints "i32"
println!("{}", type_name::()); // prints "(f64, char)"
}


,因为 ::

struct Pair {
a: T,
b: T,
}

fn print_type_name(_val: &T) {
println!("{}", std::any::type_name::());
}

fn main() {
let p1 = Pair { a: 3, b: 9 };
let p2 = Pair { a: true, b: false };
print_type_name(&p1); // prints "Pair"
print_type_name(&p2); // prints "Pair"
}


(分配在堆上的数组)就是泛型实现的:

fn main() {
let mut v1 = Vec::new();
v1.push(1);
let mut v2 = Vec::new();
v2.push(false);
print_type_name(&v1); // prints "Vec"
print_type_name(&v2); // prints "Vec"
}


,有个宏( macro
)可以通过字面方式声明 Vec

fn main() {
let v1 = vec![1, 2, 3];
let v2 = vec![true, false, true];
print_type_name(&v1); // prints "Vec"
print_type_name(&v2); // prints "Vec"
}


name![]
name!{}

fn main() {
println!("{}", "Hello there!");
}


fn main() {
use std::io::{self, Write};
io::stdout().lock().write_all(b"Hello there!\n").unwrap();
}


panic

fn main() {
let o1: Option = Some(128);
o1.unwrap(); // this is fine

let o2: Option = None;
o2.unwrap(); // this panics!
}

// output: thread 'main' panicked at 'called Option::unwrap() on a None value', src/libcore/option.rs:378:21


Option

)，它包含两个值:

enum Option {
None,
Some(T),
}

impl Option {
fn unwrap(self) -> T {
// enums variants can be used in patterns:
match self {
Self::Some(t) => t,
Self::None => panic!(".unwrap() called on a None option"),
}
}
}

use self::Option::{None, Some};

fn main() {
let o1: Option = Some(128);
o1.unwrap(); // this is fine

let o2: Option = None;
o2.unwrap(); // this panics!
}

// output: thread 'main' panicked at '.unwrap() called on a None option', src/main.rs:11:27


Result

enum Result {
Ok(T),
Err(E),
}


:

fn main() {
// x doesn't exist yet
{
let x = 42; // x starts existing
println!("x = {}", x);
// x stops existing
}
// x no longer exists
}


fn main() {
// x doesn't exist yet
{
let x = 42; // x starts existing
let x_ref = &x; // x_ref starts existing - it borrows x
println!("x_ref = {}", x_ref);
// x_ref stops existing
// x stops existing
}
// x no longer exists
}


fn main() {
let x_ref = {
let x = 42;
&x
};
println!("x_ref = {}", x_ref);
// error: x does not live long enough
}


fn main() {
let x = 42;
let x_ref1 = &x;
let x_ref2 = &x;
let x_ref3 = &x;
println!("{} {} {}", x_ref1, x_ref2, x_ref3);
}


fn main() {
let mut x = 42;
let x_ref = &x;
x = 13;
println!("x_ref = {}", x_ref);
// error: cannot assign to x because it is borrowed
}


fn main() {
let mut x = 42;
let x_ref1 = &x;
let x_ref2 = &mut x;
// error: cannot borrow x as mutable because it is also borrowed as immutable
println!("x_ref1 = {}", x_ref1);
}


fn print(x: &i32) {
// x is borrowed (from the outside) for the
// entire time this function is called.
}


• 所有使用这些引用的函数都是泛型的
• 声明周期也是泛型参数

// elided (non-named) lifetimes:
fn print(x: &i32) {}

fn print(x: &'a i32) {}


struct Number {
value: i32,
}

fn number_value(num: &'a Number) -> &'a i32 {
#.value
}

fn main() {
let n = Number { value: 47 };
let v = number_value(&n);
// v borrows n (immutably), thus: v cannot outlive n.
// While v exists, n cannot be mutably borrowed, mutated, moved, etc.
}


fn number_value(num: &'a Number) -> &'a i32 {
#.value
}

fn number_value(num: &Number) -> &i32 {
#.value
}


struct NumRef {
x: &'a i32,
}

fn main() {
let x: i32 = 99;
let x_ref = NumRef { x: &x };
// x_ref cannot outlive x, etc.
}


struct NumRef {
x: &'a i32,
}

fn as_num_ref(x: &'a i32) -> NumRef {
NumRef { x: &x }
}

fn main() {
let x: i32 = 99;
let x_ref = as_num_ref(&x);
// x_ref cannot outlive x, etc.
}


)的生命周期:

struct NumRef {
x: &'a i32,
}

fn as_num_ref(x: &i32) -> NumRef {
NumRef { x: &x }
}

fn main() {
let x: i32 = 99;
let x_ref = as_num_ref(&x);
// x_ref cannot outlive x, etc.
}


impl

impl NumRef {
fn as_i32_ref(&'a self) -> &'a i32 {
self.x
}
}

fn main() {
let x: i32 = 99;
let x_num_ref = NumRef { x: &x };
let x_i32_ref = x_num_ref.as_i32_ref();
// neither ref cannot outlive x
}


impl NumRef {
fn as_i32_ref(&self) -> &i32 {
self.x
}
}


impl NumRef {
fn as_i32_ref(&self) -> &i32 {
self.x
}
}


，它的生命周期在整个程序运行时。

:

struct Person {
name: &'static str,
}

fn main() {
let p = Person {
name: "fasterthanlime",
};
}


struct Person {
name: &'static str,
}

fn main() {
let name = format!("fasterthan{}", "lime");
let p = Person { name: &name };
// error: name does not live long enough
}


A)通过声明周期声明泛型

struct Person {
name: &'a str,
}

fn main() {
let name = format!("fasterthan{}", "lime");
let p = Person { name: &name };
// p cannot outlive name
}


B)获得这个字符串的所有权

struct Person {
name: String,
}

fn main() {
let name = format!("fasterthan{}", "lime");
let p = Person { name: name };
// name was moved into p, their lifetimes are no longer tied.
}


let p = Person { name: name };


let p = Person { name };


Rust中很多类型都有 owned

• 字符串： String
是owned, &str
是引用
• 路径： PathBuf
是owned, &Path
是引用
• 集合: Vec
是owned, &[T]
是引用

Rust有slice – 它们是对多个连续元素的引用。

fn main() {
let v = vec![1, 2, 3, 4, 5];
let v2 = &v[2..4];
println!("v2 = {:?}", v2);
}

// output:
// v2 = [3, 4]


)被 Index
IndexMut
trait重载。

..

，:

fn main() {
// 0 or greater
println!("{:?}", (0..).contains(&100)); // true
// strictly less than 20
println!("{:?}", (..20).contains(&20)); // false
// 20 or less than 20
println!("{:?}", (..=20).contains(&20)); // true
// only 3, 4, 5
println!("{:?}", (3..6).contains(&4)); // true
}


fn tail(s: &[u8]) -> &[u8] {
&s[1..]
}

fn main() {
let x = &[1, 2, 3, 4, 5];
let y = tail(x);
println!("y = {:?}", y);
}


fn tail(s: &'a [u8]) -> &'a [u8] {
&s[1..]
}


fn main() {
let y = {
let x = &[1, 2, 3, 4, 5];
tail(x)
};
println!("y = {:?}", y);
}


'static
。下面的代码就不合法:

fn main() {
let y = {
let v = vec![1, 2, 3, 4, 5];
tail(&v)
// error: v does not live long enough
};
println!("y = {:?}", y);
}


&str

fn file_ext(name: &str) -> Option {
// this does not create a new string - it returns
// a slice of the argument.
name.split(".").last()
}

fn main() {
let name = "Read me. Or don't.txt";
if let Some(ext) = file_ext(name) {
println!("file extension: {}", ext);
} else {
println!("no file extension");
}
}


fn main() {
let ext = {
let name = String::from("Read me. Or don't.txt");
file_ext(&name).unwrap_or("")
// error: name does not live long enough
};
println!("extension: {:?}", ext);
}


:

fn main() {
let s = std::str::from_utf8(&[240, 159, 141, 137]);
println!("{:?}", s);
// prints: Ok(":watermelon:")

let s = std::str::from_utf8(&[195, 40]);
println!("{:?}", s);
// prints: Err(Utf8Error { valid_up_to: 0, error_len: Some(1) })
}


:

fn main() {
let s = std::str::from_utf8(&[240, 159, 141, 137]).unwrap();
println!("{:?}", s);
// prints: ":watermelon:"

let s = std::str::from_utf8(&[195, 40]).unwrap();
// prints: thread 'main' panicked at 'called Result::unwrap()
// on an Err value: Utf8Error { valid_up_to: 0, error_len: Some(1) }',
// src/libcore/result.rs:1165:5
}


panic一个定制的信息:

fn main() {
let s = std::str::from_utf8(&[195, 40]).expect("valid utf-8");
// prints: thread 'main' panicked at 'valid utf-8: Utf8Error
// { valid_up_to: 0, error_len: Some(1) }', src/libcore/result.rs:1165:5
}


:

fn main() {
match std::str::from_utf8(&[240, 159, 141, 137]) {
Ok(s) => println!("{}", s),
Err(e) => panic!(e),
}
// prints :watermelon:
}


:

fn main() {
if let Ok(s) = std::str::from_utf8(&[240, 159, 141, 137]) {
println!("{}", s);
}
// prints :watermelon:
}


fn main() -> Result {
match std::str::from_utf8(&[240, 159, 141, 137]) {
Ok(s) => println!("{}", s),
Err(e) => return Err(e),
}
Ok(())
}


:

fn main() -> Result {
let s = std::str::from_utf8(&[240, 159, 141, 137])?;
println!("{}", s);
Ok(())
}


*

struct Point {
x: f64,
y: f64,
}

fn main() {
let p = Point { x: 1.0, y: 3.0 };
let p_ref = &p;
println!("({}, {})", p_ref.x, p_ref.y);
}

// prints (1, 3)


),那么你可以:

struct Point {
x: f64,
y: f64,
}

fn negate(p: Point) -> Point {
Point {
x: -p.x,
y: -p.y,
}
}

fn main() {
let p = Point { x: 1.0, y: 3.0 };
let p_ref = &p;
negate(*p_ref);
// error: cannot move out of *p_ref which is behind a shared reference
}

// now Point is Copy
#[derive(Clone, Copy)]
struct Point {
x: f64,
y: f64,
}

fn negate(p: Point) -> Point {
Point {
x: -p.x,
y: -p.y,
}
}

fn main() {
let p = Point { x: 1.0, y: 3.0 };
let p_ref = &p;
negate(*p_ref); // ...and now this works
}


)是实现了 Fn
FnMut
FnOnce

fn for_each_planet(f: F)
where F: Fn(&'static str)
{
f("Earth");
f("Mars");
f("Jupiter");
}

fn main() {
for_each_planet(|planet| println!("Hello, {}", planet));
}

// prints:
// Hello, Earth
// Hello, Mars
// Hello, Jupiter


fn for_each_planet(f: F)
where F: Fn(&'static str)
{
f("Earth");
f("Mars");
f("Jupiter");
}

fn main() {
let greeting = String::from("Good to see you");
for_each_planet(|planet| println!("{}, {}", greeting, planet));
// our closure borrows greeting, so it cannot outlive it
}


fn for_each_planet(f: F)
where F: Fn(&'static str) + 'static // F must now have "'static" lifetime
{
f("Earth");
f("Mars");
f("Jupiter");
}

fn main() {
let greeting = String::from("Good to see you");
for_each_planet(|planet| println!("{}, {}", greeting, planet));
// error: closure may outlive the current function, but it borrows
// greeting, which is owned by the current function
}


fn main() {
let greeting = String::from("You're doing great");
for_each_planet(move |planet| println!("{}, {}", greeting, planet));
// greeting is no longer borrowed, it is *moved* into
// the closure.
}


FnMut

fn foobar(f: F)
where F: Fn(i32) -> i32
{
println!("{}", f(f(2)));
}

fn main() {
foobar(|x| x * 2);
}

// output: 8


fn foobar(mut f: F)
where F: FnMut(i32) -> i32
{
println!("{}", f(f(2)));
// error: cannot borrow f as mutable more than once at a time
}

fn main() {
foobar(|x| x * 2);
}


fn foobar(mut f: F)
where F: FnMut(i32) -> i32
{
let tmp = f(2);
println!("{}", f(tmp));
}

fn main() {
foobar(|x| x * 2);
}

// output: 8


fn foobar(mut f: F)
where F: FnMut(i32) -> i32
{
let tmp = f(2);
println!("{}", f(tmp));
}

fn main() {
let mut acc = 2;
foobar(|x| {
acc += 1;
x * acc
});
}

// output: 24


fn foobar(f: F)
where F: Fn(i32) -> i32
{
println!("{}", f(f(2)));
}

fn main() {
let mut acc = 2;
foobar(|x| {
acc += 1;
// error: cannot assign to acc, as it is a
// captured variable in a Fn closure.
// the compiler suggests "changing foobar
// to accept closures that implement FnMut"
x * acc
});
}


FnOnce

fn foobar(f: F)
where F: FnOnce() -> String
{
println!("{}", f());
}

fn main() {
let s = String::from("alright");
foobar(move || s);
// s was moved into our closure, and our
// closures moves it to the caller by returning
// it. Remember that String is not Copy.
}


fn foobar(f: F)
where F: FnOnce() -> String
{
println!("{}", f());
println!("{}", f());
// error: use of moved value: f
}


fn main() {
let s = String::from("alright");
foobar(move || s);
foobar(move || s);
// use of moved value: s
}


fn main() {
let s = String::from("alright");
foobar(|| s.clone());
foobar(|| s.clone());
}


fn foobar(x: i32, y: i32, is_greater: F)
where F: Fn(i32, i32) -> bool
{
let (greater, smaller) = if is_greater(x, y) {
(x, y)
} else {
(y, x)
};
println!("{} is greater than {}", greater, smaller);
}

fn main() {
foobar(32, 64, |x, y| x > y);
}


fn main() {
foobar(32, 64, |_, _| panic!("Comparing is futile!"));
}


fn countdown(count: usize, tick: F)
where F: Fn(usize)
{
for i in (1..=count).rev() {
tick(i);
}
}

fn main() {
countdown(3, |i| println!("tick {}...", i));
}

// output:
// tick 3...
// tick 2...
// tick 1...


fn main() {
countdown(3, |_| ());
}


|_| ()

:

fn main() {
for i in vec![52, 49, 21] {
println!("I like the number {}", i);
}
}


fn main() {
for i in &[52, 49, 21] {
println!("I like the number {}", i);
}
}

// output:
// I like the number 52
// I like the number 49
// I like the number 21


fn main() {
// note: &str also has a .bytes() iterator.
// Rust's char type is a "Unicode scalar value"
for c in "rust".chars() {
println!("Give me a {}", c);
}
}

// output:
// Give me a r
// Give me a u
// Give me a s
// Give me a t


fn main() {
for c in "sHE'S brOKen"
.chars()
.filter(|c| c.is_uppercase() || !c.is_ascii_alphabetic())
.flat_map(|c| c.to_lowercase())
{
print!("{}", c);
}
println!();
}

// output: he's ok


fn make_tester(answer: String) -> impl Fn(&str) -> bool {
move |challenge| {
}
}

fn main() {
// you can use .into() to perform conversions
// between various types, here &'static str and String
let test = make_tester("hunter2".into());
println!("{}", test("******"));
println!("{}", test("hunter2"));
}


fn make_tester(answer: &'a str) -> impl Fn(&str) -> bool + 'a {
move |challenge| {
}
}

fn main() {
let test = make_tester("hunter2");
println!("{}", test("*******"));
println!("{}", test("hunter2"));
}

// output:
// false
// true


fn make_tester(answer: &str) -> impl Fn(&str) -> bool + '_ {
move |challenge| {
`