变量与函数
变量
变量的值默认是不可变,是不是有点诧异?叫变量却不可变:
let x = 5;println!("{}", x); // 5x = 6; // 报错,x是不可变的
复制代码
使用 mut 关键字来让变量可变:
let mut y = 5;println!("{}", y); // 5y = 6; // 加了mut之后就可以改变了println!("{}", y); // 6
复制代码
变量允许重复定义,将上一次的定义覆盖:
let z = 5;println!("{}", z); // 5let z = 6; // 重复定义println!("{}", z); // 6
// 允许改变上次的类型let spaces = "123";let spaces = spaces.len(); // 从&str变成usizeprintln!("{}", spaces); // 3
// 使用mut只能变变量值,不能改变类型let mut spaces2 = "123";spaces2 = spaces2.len() // 报错,预期一个&str,却得到一个usize
复制代码
常量使用 const 关键字来定义,名称全部大写,并显式标明数据类型:
const YEAR: u32 = 365;println!("{}", YEAR); // 365
复制代码
使用解构定义变量
从数组中解构成员:
let arr = [1, 2, 3];let [a, b, c] = arr;println!("{}-{}-{}", a, b, c); // 1-2-3
// 只解构部分成员将报错let [a,b] = arr; // 报错,预期解构3个成员
// 使用..来省略不需要的成员let [a, b, ..] = arr;
复制代码
从元组中解构成员:
let tuple = (1, "2", 3.5);let (a, b, c) = tuple;println!("{}-{}-{}", a, b, c);
// 元组中也必须结构全部成员let (a, b) = tuple; // 报错,预期解构3个成员
// 使用..来省略不需要的成员let (a, b, ..) = tuple;
复制代码
从结构体中解构属性,可以先将结构体理解成 JS 中的对象:
// 声明一个User类型的结构体struct User { name: String, age: u8,}
// 定义一个xiao_ming变量,是User结构体类型let xiao_ming = User { name: "xiaoming".to_string(), age: 18};
// 全部解构let User { name, age } = xiao_ming;println!("name:{} age:{}", name, age); // name:xiaoming age:18
// 解构部分,仍需要保证左模式与有结构相符合let User { age } = xiao_ming; // 报错,左边的模式与右边的结构不匹配,缺少age
// 使用..来省略不需要的成员let User { age, .. } = xiao_ming;println!("age:{}", age); // 18
复制代码
从枚举中结构成员,可以先简单认识下枚举,后面会有章节介绍:
// 定义一个枚举类型:Ipenum Ip { // 包含一个String类型的“变体”:V4 V4(String)}
// 定义一个Ip::V4类型的变量(双冒号可以理解为“.”),包含的值是"127.0.0.1"let localhost = Ip::V4(String::from("127.0.0.1"));
// 当枚举只有一个类型的时候我们可以直接进行解构,let后面是模式,括号中的ip是解构出来的变量let Ip::V4(ip) = localhost;println!("{}", ip); // 127.0.0.1
// 当枚举有多个类型时直接解构将报错enum Ip { V4(String), V6(String)}let Ip::V4(ip) = localhost; // 报错, 因为localhost有可能是V6类型的
// 使用if let来对多个类型进行覆盖if let Ip::V4(ip) = localhost { println!("V4: {}", ip); // 127.0.0.1 } else if let Ip::V6(ip) = localhost { println!("V6: {}", ip);} else { println!("other");}
复制代码
函数
函数使用关键字 fn 来定义,命名使用 snake case 命名方式,用下划线分割单词名称:
fn fn_name() { println!("fn_name called");}
复制代码
调用函数:
函数参数在技术文档中有两种区分:parameter 表示形参,argument 表示实参,但是我们一般不会区分,函数参数的类型必须显式注明:
foo(100); // 函数是允许调用在定义之前的fn foo(num: i32) { println!("foo called with: {}", num); // foo called with: 100}
复制代码
函数的返回值的类型也需要显式注明,使用→来标注返回值类型:
// 标明返回i32类型fn add_one(num: i32) -> i32 { return num + 1}
// return关键字可以省略fn add_two(num: i32) -> i32 { // 由于num+1后没有其他的调用,则会被为是函数的返回值 // 但是末尾不能加分号结尾 num + 2}
复制代码
函数的返回值其实是元组:
// 相当于返回了空元组:()fn foo() {}
// 相当于返回了具有一个成员的元组:(1)fn foo2() -> i32 { return 1}let num = foo2();println!("{}", num); // 1
// 所以可以返回多个成员的元组fn foo4() -> (i32, bool) { return (1, true)}let res = foo4();// 打印元组或者数组需要使用:?占位符println!("{:?}", res); // (1, true)
// 可以解构返回值let (num, boo) = foo4();println!("{}-{}", num, boo); // 1, true
// 解构返回值仍然需要解构所有成员let (num) = foo4(); // 报错,返回值的元祖中包含两个成员
// 使用..来省略不需要的成员let (num, ..) = foo4();
// 由于返回值是一个元组,所以用“.”可以取返回值的成员let tup = foo4()println!("{}", tup.0); // 1println!("{}", tup.1); // true
复制代码
函数体中的语句和表达式
语句指那些执行操作但没有返回值的指令:
// 使用let关键字创建变量并绑定值时使用的指令是一条语句let x = 2;
// let z = 5是语句,没有返回值,所以rust不允许这样做let y = (let z = 5); // 报错
复制代码
表达式则是指会进行计算并产生一个值作为结果的指令:
// 数学运算是表达式1 + 2
// 作用域块也是表达式let x = { let y = 1; // 假如在表达式的末尾加上了分号,就变为了语句而不会返回任何值 y + 2};println!("{}", x) // 3
复制代码
评论