rust学习笔记
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.
摘抄自网络,便于检索查找。

浙公网安备 33010602011771号