01.Go
- 标量(scalar):整数(signed/unsigned)、浮点数、布尔(bool)、字符(char)
- 复合(compound):元组(tuple)、数组(array)、切片(slice)
- 字符串类:
&str(字符串切片)、String - 引用与指针:
&T,&mut T,*const T,*mut T - 常用包装/错误类型:
Option<T>、Result<T, E> - 其它常见 trait/特性:Copy / Clone、Debug / Display、From/Into、AsRef/AsMut
有符号(正/负整数): i8, i16, i32, i64, i128, isize 无符号(正整数): u8, u16, u32, u64, u128, usize
类型范围
i32 => -2^31 ~ 2^31-1, u32 0 ~ 2^32
isize 范围取决于机器平台, 32 位操作系统 isize = i32, 64 位操作系统, isize = i64
i32 是绝大多数场景整数默认类型, 如类型推断 let n = 5, 不显示声明 n 默认为 i32 类型
let n8: i8 = 8; // 前置显式标注类型 let n16 = 16_i16; // 后置显式标注类型 let n32 = 32; // 使用类型推断默认类型 let n64 = 64 as i64; // 使用类型推断并强制转换类型 let nsize: isize = isize::MAX; // isize 在 64 位系统等同 i64 println!("{} is {}", n8, type_name(&n8)); println!("{} is {}", n16, type_name(&n16)); println!("{} is {}", n32, type_name(&n32)); println!("{} is {}", n64, type_name(&n64)); println!("{} is {}, isize::MAX = 2^63-1 is {}", nsize, type_name(&nsize), nsize == 2 * (2_isize.pow(62) - 1) + 1); fn type_name<T>(_: &T) -> &'static str { return std::any::type_name::<T>() } 8 is i8 16 is i16 32 is i32 64 is i64 9223372036854775807 is isize, isize::MAX = 2^64-1 is true
不同类型不能比较大小, 需转换成同一类型才可以(不同类型转换可能存在溢出)
println!("n8 < n16 is {}", n8 < n16) // 报错 39 | println!("n8 < n16 is {}", n8 < n16) | -- ^^^ expected `i8`, found `i16` | | | expected because this is `i8` | help: you can convert `n8` from `i8` to `i16`, matching the type of `n16` | 39 | println!("n8 < n16 is {}", i16::from(n8) < n16) | ++++++++++ + println!("n8 < n16 is {}", i16::from(n8) < n16) // n8 转为 i6 类型 n8 < n16 is true
常用整数属性或方法
i32::MAX // i32 类型的最大值(2^31-1) i32::MIN // i32 类型最小值(-2^31) let n:i32 = i32::from(3_i8); // 转换成 i32 类型 println!("n is {}", n); println!("n.abs() is {}", n.abs()); // 获取绝对值 println!("n.pow(3) is {}", n.pow(3)); // 幂运算 println!("n.is_positive() is {}", n.is_positive()); // 判断是否正数 println!("n.is_negative() is {}", n.is_negative()); // 判断是否正数 n is 3 n.abs() is 3 n.pow(3) is 27 n.is_positive() is true n.is_negative() is false
f32, f64
浮点数默认为 f64
let inf = f64::INFINITY; let f = 3.1415; f.floor(); // 3.0 向下取整 f.ceil(); // 4.0 向上取整 f.round(); // 3.0 四舍五入 f.is_nan(); // false 判断是否为 nan f.is_infinite(); // false 判断为正无穷或负无穷 f.max(1.414); // 3.1415 与 1.414 比较,返回更大的浮点数 f.min(1.414); // 1.414 与 1.414 比较,返回更小的浮点数
布尔类型(占用 1 byte): true, false
let t = true; // 布尔类型不支持后缀类型(true_bool 会报错) let f: bool = false;
所有 Unicode 值都可以作为 RUST 字符, 单个字符占用 4 个字节
所有 char 类型都可以转为 u32
0 到 0x10FFFF u32 数值可以转为 char
char 类型必须使用单引号且字符数量为 1, 如 ‘A’, ‘字’, ’ ’, 空字符 ” 不是 char 类型
for i in 'a'..='z' { print!("{i}"); } abcdefghijklmnopqrstuvwxyz println!("ascii 67 is {:?}", char::from_u32(65_u32).unwrap()); println!("char B to u32 {}", 'B' as u32); ascii 67 is 'A' char B to u32 66
RUST 引入所有权和借用的概念, 每个一个值只能被一个变量拥有
部分类型数据赋值为了满足值只能被一个变量拥有, 会同时将所有权一同转移, 原有变量赋值后无法使用
部分类型赋值时通过 Copy 赋值不会转移所有权, 原有变量仍然可用
Copy 类型有: 整数, 浮点数, 布尔值, 字符
非 Copy 类型带有传染性, 复杂类型只要包含就会变成非 Copy 类型
let m: String = String::from("owner"); // 创建 String 类型字符串(可变长,所有权可变) let n = m; // m 的值和所有权传递给 n, m 不再可用 println!("check m {}", m); println!("check m {}", m); ^ value borrowed here after move
字符串有两种
- String: 可变长度, 拥有所有权, 在堆上创建, 速度较慢
- &str: 字符串默认类型, 无所有权, 不可变, 在栈中, 速度快
let s = "static str" // 创建 &str 类型
元组是一个若干不同类型的值打包而成, 生成后数量不可变, 可使用序号取值
// 创建元组并自行推断类型 (u8, u16, u32) let tup = (8_u8, 16_u16, 32_u32); println!("tuple is {:?}", tup); tuple is (8, 16, 32) // 通过元组解包赋值, 元组使用序号取值 let (x, y, z) = (tup.0, tup.1, tup.2); println!("x:{x} y:{y} z:{z}"); x:8 y:16 z:32 // 使用元组返回多个值 let (a, b, c) = return_tuple(); fn return_tuple() -> (u8, u16, u32) { return (8_u8, 16_u16, 32_u32) } // 数组转为元组 let array: [i32; 3] = [1,2,3]; let tup: (i32, i32, i32) = array.into();
- 长度固定
- 数组所有元素类型相同
- 有固定顺序, 线性排列
let list1 = [1,2,3]; // 类型推断 类型 i32, 长度为 3 let list2: [i32; 3] = [1,2,3]; // 与 list1 完全一致 let list3 = [8_i8; 4]; // 快速生成 i8 类型, 长度为 4 数组 [8,8,8,8] // 元组转数组 let tuple: (i32, i32, i32) = (1, 2, 3); let array: [i32; 3] = tuple.into(); println!("tuple transf list {:?}", array); list1.len() // 非 Copy 类型数组直接遍历会消耗元素所有权 let array = [String::from("John"), String::from("Lily")]; for i in array { println!("value: {}", i); // 会消耗元素所有权, array 遍历后不可用 } println!("array: {:?}", array); println!("array: {:?}", array); ^^^^^ value borrowed here after move // 使用 iter() 遍历不消耗使用权 for i in array.iter() { println!("value: {}", i); // 不消耗元素所有权, array 遍历后仍可用 } println!("array: {:?}", array); value: John value: Lily array: ["John", "Lily"]