rust众多数据类型可以高效利用底层空间
// rust中的基本类型
// 整数类型
// 有符号整数
let _i8: i8 = 0;
let _i16: i16 = 0;
let _i32: i32 = 0;
let _i64: i64 = 0;
let _i128: i128 = 0;
let _isize: isize = 0;
// 无符号整数
let _u8: u8 = 0;
let _u16: u16 = 0;
let _u32: u32 = 0;
let _u64: u64 = 0;
let _u128: u128 = 0;
let _usize: usize = 0;
// 浮点数类型
let _f32: f32 = 0.0;
let _f64: f64 = 0.0;
// 布尔类型
let _bool: bool = true;
// 字符类型
let _char: char = 'a';
// 数组类型
let _array: [i32; 5] = [1, 2, 3, 4, 5];
// 元组类型
let _tuple: (i32, f64, u8) = (500, 6.4, 1);
// 元组的解构
let (_x, _y, _z) = _tuple;
println!("The value of y is: {}", _y);
// 元组的索引
let _five_hundred = _tuple.0;
let _six_point_four = _tuple.1;
let _one = _tuple.2;
所有权
所有权规则
首先,让我们看一下所有权的规则。当我们通过举例说明时,请谨记这些规则:
Rust 中的每一个值都有一个 所有者(owner)。
变量作用域
硬编码字符串(字面量),仅在作用域内有效
{ // s 在这里无效, 它尚未声明
let s = "hello"; // 从此处起,s 是有效的
// 使用 s
}
String
Rust 有第二个字符串类型,String
。这个类型管理被分配到堆上的数据,所以能够存储在编译时未知大小的文本。可以使用 from
函数基于字符串字面值来创建 String
,如下:
let s = String::from("hello");
使其可修改
let mut s = String::from("hello");
对于 String
类型,为了支持一个可变,可增长的文本片段,需要在堆上分配一块在编译时未知大小的内存来存放内容。这意味着:
必须在运行时向内存分配器(memory allocator)请求内存。
需要一个当我们处理完 String
时将内存返回给分配器的方法。
变量与数据交互的方式(一):移动
为了确保内存安全,在 let s2 = s1
之后,Rust 认为 s1
不再有效,因此 Rust 不需要在 s1
离开作用域后清理任何东西。
fn main() {
let s1 = String::from("hello");
let s2 = s1;
}
Rust 永远也不会自动创建数据的 “深拷贝”。因此,任何 自动 的复制可以被认为对运行时性能影响较小。
变量与数据交互的方式(二):克隆
如果我们 确实 需要深度复制 String
中堆上的数据,而不仅仅是栈上的数据,可以使用一个叫做 clone
的通用函数。第五章会讨论方法语法,不过因为方法在很多语言中是一个常见功能,所以之前你可能已经见过了。
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2);
只在栈上的数据:拷贝
let x = 5;
let y = x;
println!("x = {}, y = {}", x, y);
所有权与函数
将值传递给函数与给变量赋值的原理相似。向函数传递值可能会移动或者复制
fn main() {
let s = String::from("hello"); // s 进入作用域
takes_ownership(s); // s 的值移动到函数里 ...
// ... 所以到这里不再有效
let x = 5; // x 进入作用域
makes_copy(x); // x 应该移动函数里,
// 但 i32 是 Copy 的,
// 所以在后面可继续使用 x
} // 这里, x 先移出了作用域,然后是 s。但因为 s 的值已被移走,
// 没有特殊之处
fn takes_ownership(some_string: String) { // some_string 进入作用域
println!("{}", some_string);
} // 这里,some_string 移出作用域并调用 `drop` 方法。
// 占用的内存被释放
fn makes_copy(some_integer: i32) { // some_integer 进入作用域
println!("{}", some_integer);
} // 这里,some_integer 移出作用域。没有特殊之处
返回值与作用域
返回值也可以转移所有权
fn main() {
let s1 = gives_ownership(); // gives_ownership 将返回值
// 转移给 s1
let s2 = String::from("hello"); // s2 进入作用域
let s3 = takes_and_gives_back(s2); // s2 被移动到
// takes_and_gives_back 中,
// 它也将返回值移给 s3
} // 这里, s3 移出作用域并被丢弃。s2 也移出作用域,但已被移走,
// 所以什么也不会发生。s1 离开作用域并被丢弃
fn gives_ownership() -> String { // gives_ownership 会将
// 返回值移动给
// 调用它的函数
let some_string = String::from("yours"); // some_string 进入作用域.
some_string // 返回 some_string
// 并移出给调用的函数
//
}
// takes_and_gives_back 将传入字符串并返回该值
fn takes_and_gives_back(a_string: String) -> String { // a_string 进入作用域
//
a_string // 返回 a_string 并移出给调用的函数
}
引用
引用(reference)像一个指针,因为它是一个地址,我们可以由此访问储存于该地址的属于其他变量的数据。 与指针不同,引用确保指向某个特定类型的有效值
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
//无法修改
s.len()
}
&s1
语法让我们创建一个 指向 值 s1
的引用,但是并不拥有它。因为并不拥有这个值,所以当引用停止使用时,它所指向的值也不会被丢弃。
可变引用
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
可变引用有一个很大的限制:如果你有一个对该变量的可变引用,你就不能再创建对该变量的引用。这些尝试创建两个 s
的可变引用的代码会失败:
fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
println!("{}, {}", r1, r2);
}
不同作用域可以拥有同一引用
fn main() {
let mut s = String::from("hello");
{
let r1 = &mut s;
} // r1 在这里离开了作用域,所以我们完全可以创建一个新的引用
let r2 = &mut s;
}
哇哦!我们 也 不能在拥有不可变引用的同时拥有可变引用。
fn main() {
let mut s = String::from("hello");
let r1 = &s; // 没问题
let r2 = &s; // 没问题
let r3 = &mut s; // 大问题
println!("{}, {}, and {}", r1, r2, r3);
}
可以
fn main() {
let mut s = String::from("hello");
let r1 = &s; // 没问题
let r2 = &s; // 没问题
println!("{} and {}", r1, r2);
// 此位置之后 r1 和 r2 不再使用
let r3 = &mut s; // 没问题
println!("{}", r3);
}
引用的规则
让我们概括一下之前对引用的讨论:
在任意给定时间,要么 只能有一个可变引用,要么 只能有多个不可变引用。
Slice 类型
slice 允许你引用集合中一段连续的元素序列,而不用引用整个集合。slice 是一类引用,所以它没有所有权。
fn main() {
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];
}
结构体
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}