rust学习笔记

RsProxy

Rust语言设置国内镜像 - 梅花Q - 博客园 (cnblogs.com)

Rust 程序设计语言 (rust-lang.org) Rust 程序设计语言 (rust-lang.org)

 

查看代码
 use std::io;
use rand::Rng;
use std::cmp::Ordering;


fn main() {
    println!("Guess the number!");

    let /*mut*/ secret_number = rand::thread_rng().gen_range(1..=100);

    println!("The secret number is:{secret_number}");
    loop {
        println!("Please input your guess.");

        let mut guess = String::new();
        // let apples = 5; // immutable
        // let /*mut */bananas = 5; // mutable

        /*let result=*/    io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read line");
        let guess: u32 = match guess.trim().parse()
        {
            Ok(num) => num,
            Err(_) => {
                println!("please input a num!!");
                continue;
            }
        };
        // println!("You guessed: {guess},apples = {apples},bananas={bananas}");
        println!("You guessed: {guess}");
        match guess.cmp(&secret_number) {
            Ordering::Less => println!("Too small!"),
            Ordering::Greater => println!("Too big"),
            Ordering::Equal => {
                println!("You Win!");
                break;
            }
        }
        // let x = 5;
        // let y = 10;
        //
        // println!("x = {x} and y + 2 = {}", y + 2);
    }
}
查看代码
 use std::io;
use std::io::stdout;

fn main() {
 /*   let x = 5;
    println!("The value of x is: {x}");

    //x = 6;//  help: consider making this binding mutable: `mut x`
    println!("The value of x is: {x}");*/
    let mut x = 5;//标记变量
    println!("The value of x is: {x}");
    x = 6;
    println!("The value of x is: {x}");

    const /*mut 不允许*/ THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;//Rust 的常量命名约定是全部大写,单词之间使用下划线。
    println!("the THREE_HOURS_IN_SECONDS value is {}",THREE_HOURS_IN_SECONDS);


    let x = 5;

    let x = x + 1;//遮蔽,实际上是在创建一个新变量

    {
        let x = x * 2;
        println!("The value of x in the inner scope is: {x}");
    }

    println!("The value of x is: {x}");
    let spaces = "   ";
    let spaces = spaces.len();
    println!("spaces ={}", spaces);
    //如果我们尝试使用mut此方法,如下所示,我们将收到编译时错误:
    // let mut spaces = "   ";
        // spaces = spaces.len();//expected `&str`, found `usize`
    //标量和复合,标量类型表示单个值。 Rust 有四种主要标量类型:整数、浮点数、布尔值和字符。
    let guess: u32 = "42".parse().expect("Not a number!");
//i8 u8 i16 u16 i32 u32 i64 u64 i128 u128 arch:isize usize
    //有符号和无符号是指数字是否可能为负数,有符号数使用二进制补码表示形式存储。
    //isize和usize类型取决于程序运行所在计算机的体系结构
    //如果您使用的是 64 位体系结构,则为 64 位;如果您使用的是 32 位体系结构,则为 32 位。 32 位架构
    //57u8 来指定类型,用作_视觉分隔符,十六进制	0xff,八进制	0o77,二进制	0b1111_0000,字节(u8仅)	b'A'
    //整数类型默认为i32.使用isizeor的主要情况usize是对某种集合建立索引时。

    //显式处理溢出的可能性,1.wrapping_*,例如wrapping_add.
    //None如果方法溢出,则返回该值checked_*。
    // 返回值和一个布尔值,指示方法是否存在溢出overflowing_*。
    // 使用这些方法在值的最小值或最大值处饱和saturating_* 。

    //f32和f64,其大小分别为 32 位和 64 位。默认类型是f64 因为在现代 CPU 上,它的速度大致相同,f32但精度更高。所有浮点类型都有符号。
    let x = 2.0; // f64

    let y: f32 = 3.0; // f32

    println!("guess={},x={},y={}", guess,x, y);
//整数除法将零截断为最接近的整数。

// addition
    let sum = 5 + 10;

    // subtraction
    let difference = 95.5 - 4.3;

    // multiplication
    let product = 4 * 30;

    // division
    let quotient = 56.7 / 32.2;
    let truncated = -5 / 3; // Results in -1

    // remainder
    let remainder = 43 % 5;

    let t = true;

    let f: bool = false; // with explicit type annotation

    println!("sum={sum},difference={difference},product={product},quotient={quotient}\
    truncated={truncated},remainder={remainder},t={t},f={f}");

    let c = 'z';
    let z: char = 'ℤ'; // with explicit type annotation
    let heart_eyed_cat = '😻';

    println!("c={c},z={z},heart_eyed_cat={heart_eyed_cat}");
//char类型大小为 4 个字节,表示 Unicode 标量值,这意味着它可以表示的不仅仅是 ASCII。重音字母;中文、日文、韩文字符;表情符号;和零宽度空格都是charRust 中的有效值。 Unicode 标量值的范围从U+0000到U+D7FF到包括U+E000在内U+10FFFF。

    let tup: (i32, f64, u8) = (500, 6.4, 1);
     // println!("tup={}",tup);//元组中不同值的类型不必相同,can't display
    // 可以使用模式匹配来解构元组值
    let tup2 = (500, 6.4, 1);

    let (x, y, z) = tup2;

    print!("The value of y is: {y}.");
    let x: (i32, f64, u8) = (500, 6.4, 1);

    let five_hundred = x.0;

    let six_point_four = x.1;

    let one = x.2;//使用句点 . 后跟要访问的值的索引 来直接访问元组元素
    print!("five_hundred={five_hundred},six_point_four={six_point_four},one={one}");
//没有任何值的元组有一个特殊的名称,unit。该值及其对应的类型都被写入()并表示空值或空返回类型。如果表达式不返回任何其他值,则它们隐式返回单位值
    //数组的每个元素必须具有相同的类型
    let a = [1, 2, 3, 4, 5];
    // print!("a={a}");//cannot be formatted with the default formatter
//将数据分配在堆栈而不是堆上,矢量是标准库提供的类似集合类型,允许大小增长或缩小。
    let a: [i32; 5] = [1, 2, 3, 4, 5];
    let months = ["January", "February", "March", "April", "May", "June", "July",
        "August", "September", "October", "November", "December"];
    let a = [3; 5];//指定初始值、后跟分号、然后在方括号中指定数组的长度来初始化数组,使其每个元素包含相同的值=let a = [3, 3, 3, 3, 3];

    let first = a[0];
    let second = a[1];

    println!("first={first},second={second}");//超出数组末尾的数组元素会发生什么
    let a = [1, 2, 3, 4, 5];

    println!("Please enter an array index.");

    let mut index = String::new();

    io::stdin()
        .read_line(&mut index)
        .expect("Failed to read line");

    let index: usize = index
        .trim()
        .parse()
        .expect("Index entered was not a number");

    let element = a[index];

    println!("The value of the element at index {index} is: {element}");//输入超出数组末尾的数字
    //index out of bounds: the len is 5 but the index is
    another_function();
    another_function2(5);
    print_labeled_measurement(5, 'h');

    let y = {
        let x = 3;
        x + 1
    };

    println!("The value of y is: {y}");
    let x = five();//有返回值的函数


    println!("The value of x is: {x}");
    let x = plus_one(5);

    println!("The value of x is: {x}");
    let number = 3;

    if number < 5 {//always true,if not a bool:expected `bool`, found
        println!("condition was true");
    } else {
        println!("condition was false");
    }

    if number != 0 {
        println!("number was something other than zero");
    }
    if number % 4 == 0 {//Rust 只执行第一个条件的块true ,一旦找到一个条件,它甚至不会检查其余的条件。
        println!("number is divisible by 4");
    } else if number % 3 == 0 {
        println!("number is divisible by 3");
    } else if number % 2 == 0 {
        println!("number is divisible by 2");
    } else {
        println!("number is not divisible by 4, 3, or 2");
    }
    let condition = true;
    let number = if condition { 5 } else { 6 };
//如果类型不匹配,如下例所示,我们将收到错误: let number = if condition { 5 } else { "six" };
    println!("The value of number is: {number}");

    loop {
        println!("again!->break;");
        break;
    }
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;
        }
    };

    println!("The result is {result}");

    main_loop_label();

    let mut number = 3;

    while number != 0 {
        println!("{number}!");

        number -= 1;
    }

    println!("LIFTOFF!!!");


    let a = [10, 20, 30, 40, 50];
    let mut index = 0;

    while index < 5 {//for
        println!("the value is: {}", a[index]);

        index += 1;
    }

    let a = [10, 20, 30, 40, 50];

    for element in a {
        println!("the value is: {element}");
    }


    for number in (1..4).rev() {//rev来反转范围的倒计时,not include 4
        println!("{number}!");
    }
    println!("LIFTOFF!!!");


}
fn main_loop_label() {
    let mut count = 0;
    'counting_up: loop {
        println!("count = {count}");
        let mut remaining = 10;

        loop {
            println!("remaining = {remaining}");
            if remaining == 9 {
                break;
            }
            if count == 2 {
                break 'counting_up;
            }
            remaining -= 1;
        }

        count += 1;
    }
    println!("End count = {count}");
}

fn another_function() {//并不关心你在哪里定义函数,只关心它们是在调用者可以看到的范围内的某个地方定义的。
    println!("Another function.");
}
fn another_function2(x: i32) {
// fn another_function(x: i32) {//签名中,必须声明每个参数的类型
    println!("The value of x is: {x}");
}
fn print_labeled_measurement(value: i32, unit_label: char) {
    println!("The measurement is: {value}{unit_label}");
}
//陈述和表达式,语句是执行某些操作但不返回值的指令。表达式计算结果值。let是一条语句
//语句不返回值。因此,您不能将let语句分配给另一个变量,如以下代码尝试执行的操作;你会得到一个错误:
//let x = (let y = 6);//let y = 6语句不返回值
fn five() -> i32 {
    5//函数体是一个5没有分号的孤独函数
}

fn plus_one(x: i32) -> i32 {
    // x + 1;//收到错误//implicitly returns `()` as its body has no tail or `return` expression,help: remove this semicolon to return this value

    x + 1
}
查看代码
 fn main() {
    // let s = String::from("hello");

    let mut s = String::from("hello");

    s.push_str(", world!"); // push_str() appends a literal to a String
    {
        let s2 = String::from("hello2"); // s is valid from this point forward
        // let s3:String = String::from("hello2"); // s is valid from this point forward

        // do stuff with s
        println!("{}", s2);
    } // this scope is now over, and s is no, Rust 在右大括号处自动调用 drop
    // longer valid
    println!("{}", s); // This will print `hello, world!`

    let x = 5;
    let y = x;

    println!("{},{}", x, y);//这意味着我们没有理由在创建变量 y 后阻止 x 有效
    //如果类型或其任何部分实现了 Drop 特征,Rust 不会让我们用 Copy 注释类型。
    //如果某个类型实现了 Copy 特征,则使用它的变量不会移动,而是会被简单地复制,从而使它们在分配给另一个变量后仍然有效。

//任何一组简单标量值都可以实现 Copy ,并且不需要分配或某种形式的资源可以实现 Copy,[元组],如果它们仅包含也实现 Copy 的类型。但 (i32, String) 没有实现。
    let s1 = String::from("helloS1");
    let s2 = s1;
    // println!("{},world!2", s1);//borrow of moved value: `s1`
    println!("{},world!2", s2);//只有 s2 有效,当它超出范围时,它会单独释放内存

    let s3 = s2.clone();

    println!("s1 = {}, s2 = {}", s2, s3);//代码可能很昂贵

    //将变量传递给函数将会移动或复制,就像赋值一样。

    let s = String::from("helloNew");  // s comes into scope

    takes_ownership(s);             // s's value moves into the function...
    // ... and so is no longer valid here
    //在调用 takes_ownership 之后尝试使用 s ,Rust 会抛出编译时错误
    // println!("s={}", s);//value borrowed here after move

    let x = 5;                      // x comes into scope

    makes_copy(x);                  // x would move into the function,
    // but i32 is Copy, so it's okay to still
    // use x afterward
    print!("x={}", x);

    //返回值也可以转移所有权
    let s1 = gives_ownership();         // gives_ownership moves its return
    // value into s1
    println!("s1={s1}");
    let s2 = String::from("hello");     // s2 comes into scope
    // let s3 = takes_and_gives_back(s2);  // s2 is moved into
    let s3 = takes_and_gives_back(s2);  // s2 is moved into
    // takes_and_gives_back, which also
    // moves its return value into s3
    // println!("s2={s2},s3={s3}");//borrow of moved value: `s2`
//变量的所有权每次都遵循相同的模式:将值分配给另一个变量会移动它。当包含堆上数据的变量超出范围时,该值将被 drop 清除,除非数据的所有权已移至另一个变量。
    println!("s3={s3}");

    let s1 = String::from("hello");

    let (s2, len) = calculate_length(s1);

    // let (s1, len) = calculate_length(s1);
    //println!("s1 is s2 '{}' is {}.", s1, s2);//Rust 有一个使用值而不转移所有权的功能,称为引用。
    println!("The length of '{}' is {}.", s2, len);//Rust 有一个使用值而不转移所有权的功能,称为引用。

    let s1 = String::from("helloRef");

    let len = calculate_length_ref(&s1);//&s1 语法允许我们创建一个引用 s1 的值但不拥有它的引用。
    //因为它不拥有它,所以当引用停止使用时,它指向的值不会被删除。

    println!("The Ref length of '{}' is {}.", s1, len);
    // change(&s1);

    let mut s_mut = String::from("helloMut");

    change_mut(&mut s_mut);

    println!("{s_mut}");
//如果您有一个对某个值的可变引用,则不能有对该值的其他引用。尝试创建两个对 s 的可变引用的代码将失败:
    let mut s = String::from("hello");

    let r1 = &mut s;
    // let r2 = &mut s;//cannot borrow `s` as mutable more than once at a time

    // println!("{}, {}", r1, r2);
    println!("{}", r1);//一次不能多次借用 s 作为可变对象

    let mut s = String::from("hello");

    {
        // let r1 = &mut s;//warn unused_variables
    } // r1 goes out of scope here, so we can make a new reference with no problems.

    let r2 = &mut s;
    println!("{}, {}  r1 goes out of scope here, so we can make a new reference with no problems.", r1, r2);

//当我们拥有相同值的不可变引用时,我们也不能拥有可变引用。
    /*    let mut s = String::from("hello");

        let r1 = &s; // no problem
        let r2 = &s; // no problem
        // let r3 = &mut s; // BIG PROBLEM,cannot borrow `s` as mutable because it is also borrowed as immutable
        //
        // println!("{}, {}, and {}", r1, r2, r3);
        println!("{}, {}, and {}", r1, r2,s);*/
//不可变引用的用户不会期望其值会突然发生变化!然而,多个不可变引用是允许的,因为仅仅读取数据的人没有能力影响其他人对数据的读取。
    let mut s = String::from("hello");

    let r1 = &s; // no problem
    let r2 = &s; // no problem
    println!("{} and {}", r1, r2);
    // variables r1 and r2 will not be used after this point
//不可变引用 r1 和 r2 的作用域在它们上次使用的 println! 之后结束,即可变引用 r3 之前被建造。这些作用域不重叠,因此允许使用此代码:编译器可以判断在作用域结束之前的某个点不再使用该引用。

    let r3 = &mut s; // no problem
    // println!("{}", r2);//err
    println!("{}", r3);

//编译器保证引用永远不会是悬空引用:如果您引用了某些数据,编译器将确保数据不会在数据引用超出范围之前超出范围。
//     let reference_to_nothing = dangle();
//expected named lifetime parameter
//     |
//     = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
// help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`

    //切片是一种引用,因此它没有所有权。

    let mut s = String::from("xxxx5 yyyyy");

    let word = first_word(&s); // word will get the value 5

    s.clear(); // this empties the String, making it equal to ""
    println!("word len={word}");//因为 word 根本没有连接到 s 的状态,所以 word 仍然包含值 5
    // word still has the value 5 here, but there's no more string that
    // we could meaningfully use the value 5 with. word is now totally invalid!

    let s = String::from("hello world");

    let hello = &s[0..5];//hello 不是对整个 String 的引用,而是对 String 的一部分的引用,在额外的 [0..5] 位中指定。我们通过指定 [starting_index..ending_index] 使用括号内的范围创建切片
    let world = &s[6..11];
    //let slice = &s[0..2];==    let slice = &s[..2];
//let len = s.len(); let slice = &s[3..len]; == let slice = &s[3..];
//let slice = &s[0..len];== let slice = &s[..];
    //字符串切片范围索引必须出现在有效的 UTF-8 字符边界处。如果您尝试在多字节字符的中间创建字符串切片,您的程序将错误退出。
    let mut s = String::from("hello world");
    // s.clear();//ok
    let word = first_word_fix(&s);
//借用规则,如果我们对某个东西有一个不可变的引用,我们就不能同时使用一个可变的引用。

    //s.clear(); // error!cannot borrow `s` as mutable, as it is not declared as mutable,^^^^^^^^^ mutable borrow occurs here

    println!("the first word is: {}", word);
//因为 clear 需要截断 String ,所以它需要获取可变引用。调用 clear 之后的 println! 使用 word 中的引用,因此此时不可变引用必须仍然处于活动状态。 Rust 不允许 clear 中的可变引用和 word 中的不可变引用同时存在,并且编译失败。

    // let s = "Hello, world!";
    // 这里 s 的类型是 &str :它是一个指向二进制文件特定点的切片。这也是字符串文字不可变的原因; &str 是一个不可变的引用。
//fn first_word(s: &String) -> &str { == fn first_word(s: &str) -> &str {;对 &String 值和 &str 值使用相同的函数
//如果我们有一个字符串切片,我们可以直接传递它。利用了 deref 强制转换,“使用函数和方法进行隐式 Deref 强制转换
    let my_string = String::from("hello world");

    // `first_word` works on slices of `String`s, whether partial or whole
    let word = first_word_fix_new(&my_string[0..3]);
    let word = first_word_fix_new(&my_string[..3]);
    // `first_word` also works on references to `String`s, which are equivalent
    // to whole slices of `String`s
    let word = first_word_fix(&my_string);
    println!("2word = {word}");
    let my_string_literal = "hello world";

    // `first_word` works on slices of string literals, whether partial or whole
    let word = first_word_fix_new(&my_string_literal[0..3]);
    // let word = first_word_fix(&my_string_literal[..]);//expected `&String`, but found `&str`
    // let word = first_word_fix_new(&my_string_literal[..]);

    // Because string literals *are* string slices already,
    // this works too, without the slice syntax!
    // let word = first_word_fix_new(my_string_literal[..3]);//&str 是一个不可变的引用。expected `&str`, but found `str`
    let word = first_word_fix_new(my_string_literal);//&str 是一个不可变的引用。

    println!("22word = {word}");

    let a = [1, 2, 3, 4, 5];

    let slice = &a[1..3];

    // assert_ne!(slice, &[2, 3]);//failed
    assert_eq!(slice, &[2, 3]);//该切片的类型为 &[i32] 。它的工作方式与字符串切片相同


}
fn first_word_fix_new(s: &str) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}
fn first_word_fix(s: &String) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

fn first_word(s: &String) -> usize {
    let bytes = s.as_bytes();//需要逐个元素地遍历 String 并检查值是否为空格,所以我们将使用 as_bytes

    for (i, &item) in bytes.iter().enumerate() {//创建一个迭代器
        if item == b' ' {
            return i;//返回该位置。否则,我们使用 s.len() 返回字符串的长度
        }
    }

    s.len()//但它只是 &String 上下文中的一个有意义的数字。换句话说,因为它是与 String 不同的值,所以不能保证它在将来仍然有效。
}

/*fn dangle() -> &String {// missing lifetime specifier
    let s = String::from("hello");
//该函数的返回类型包含一个借用的值,但没有可供借用的值
    &s
}

fn dangle() -> &String { // dangle returns a reference to a String

    let s = String::from("hello"); // s is a new String

    &s // we return a reference to the String, s
} // Here, s goes out of scope, and is dropped. Its memory goes away.
  // Danger!
  //因为 s 是在 dangle 内部创建的,所以当 dangle 的代码完成时, s 将被释放。但我们试图返回对它的引用。这意味着此引用将指向无效的 String 。这样可不行啊! Rust 不会让我们这样做。

*/
fn no_dangle() -> String {
    let s = String::from("hello");

    s//这工作没有任何问题。所有权被移出,并且没有任何内容被释放。
}
// Here, x goes out of scope, then s. But because s's value was moved, nothing
// special happens.
// Here, s3 goes out of scope and is dropped. s2 was moved, so nothing
// happens. s1 goes out of scope and is dropped.
/*fn change(some_string: &String) {
    some_string.push_str(", world");//cannot borrow `*some_string` as mutable, as it is behind a `&` reference
}*/


fn change_mut(some_string: &mut String) {//这非常清楚地表明 change 函数将改变它借用的值。
    some_string.push_str(", world");
}

fn calculate_length_ref(s: &String) -> usize {//与使用 & 引用相反的是取消引用,这是通过取消引用运算符 * 完成的
    s.len()// s is a reference to a String
}// Here, s goes out of scope. But because it does not have ownership of what
// it refers to, it is not dropped.但是当 s 停止使用时,引用指向的值不会被删除,因为 s 没有所有权。
//当函数将引用而不是实际值作为参数时,我们不需要返回值来归还所有权,因为我们从未拥有所有权。

fn calculate_length(s: String) -> (String, usize) {
    let length = s.len(); // len() returns the length of a String

    (s, length)
}

fn gives_ownership() -> String {             // gives_ownership will move its
    // return value into the function
    // that calls it

    let some_string = String::from("yours"); // some_string comes into scope

    some_string                              // some_string is returned and
    // moves out to the calling
    // function
}

// This function takes a String and returns one
fn takes_and_gives_back(a_string: String) -> String { // a_string comes into
    // scope

    a_string  // a_string is returned and moves out to the calling function
}

fn takes_ownership(some_string: String) { // some_string comes into scope
    println!("{}", some_string);
} // Here, some_string goes out of scope and `drop` is called. The backing
// memory is freed.

fn makes_copy(some_integer: i32) { // some_integer comes into scope
    println!("{}", some_integer);
} // Here, some_integer goes out of scope. Nothing special happens.
posted @ 2024-04-07 21:51  CharyGao  阅读(14)  评论(0)    收藏  举报