在入门的时候并不能全方位地看待问题,有时候会忽略一些显而易见的知识,现在回过头梳理,把前面的补起来。
let ident = expr;
发生的是复制还是移动?
- 当赋值时,所有实现了
Copy
trait的赋值会发生复制,它会复制一份在栈上的值。 - 当赋值时,其它情况会发生转移。这时栈上会复制一份指针,但指向的堆上的实际值不变,会发生所有权的转移。
- 如果某个类型或它的任意一部分实现了
Drop
trait,那么就不能再实现Copy
trait。
我们来看一个新手很容易碰到的问题:
pub fn copy_test() {
// 复制
let num1: i32 = 666;
let num2: i32 = num1;
println!("{}", num1);
println!("{}", num2);
}
pub fn move_test() {
// 移动
#[derive(Debug)]
struct Point(i32, i32);
let p1 = Point(0, 0);
let p2 = p1;
// println!("{:?}", p1); // 这一句去掉注释会报错
println!("{:?}", p2);
}
为了解决以上问题,有三种常见的解决办法。
- 使用引用
pub fn ref_test() {
// 移动
#[derive(Debug)]
struct Point(i32, i32);
let p1 = &Point(0, 0);
let p2 = &p1;
println!("{:?}", p1); //
println!("{:?}", p2);
}
- 克隆该值再赋值
pub fn clone_test() {
#[derive(Debug,Clone)]
struct Point(i32, i32);
let p1 = Point(0, 0);
let p2 = p1.clone();
println!("{:?}", p1); //
println!("{:?}", p2);
}
- 为该类型实现
Copy
trait
pub fn move_copy_test() {
struct Point(i32, i32);
impl std::fmt::Display for Point {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("Point:({}, {})", self.0, self.1))
}
}
impl Clone for Point {
fn clone(&self) -> Self {
Self(self.0.clone(), self.1.clone())
}
}
impl Copy for Point {}
let p1 = Point(1, 1);
let p2 = p1;
println!("p1: {}", p1); // 不实现 Copy trait 此处会报错
println!("p2: {}", p2);
}
为类型实现+
、==
等操作
这个比较简单,实现相应的trait即可。
pub fn implement_symbol_add_eq_trait() {
// #[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
impl std::fmt::Debug for Point {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Point")
.field("x", &self.x)
.field("y", &self.y)
.finish()
}
}
impl PartialEq<Point> for Point {
fn eq(&self, other: &Point) -> bool {
self.x == other.x && self.y == other.y
}
}
impl std::ops::Add<&Point> for Point {
type Output = Self;
fn add(self, other: &Point) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
let p1 = Point { x: 1, y: 1 };
let p2 = Point { x: 1, y: 1 };
println!("p1 == p2: {}", p1 == p2);
println!("p1 + &p2: {:?}", p1 + &p2);
}
为A trait
相关的的类型实现B trait
举个例子,类型A实现了From<i32>
trait,这个trait干什么呢?
它有个从i32产生的“构造函数”TypeA::from(i32)
。
那么我们很可能有另外一种into
写法,如下:
let ta: TypeA = TypeA::from(666);
let ta: TypeA = 666.into();
这是怎么实现的呢?
pub fn implement_into_for_from_trait() {
trait From<T>: Sized {
fn from0(val: T) -> Self;
}
trait Into<T>: Sized {
fn into0(&self) -> T;
}
// 假设T1实现了From<T2>, 且T2实现了Clone
// 我们为T2实现Into<T1>
impl<T1: From<T2>, T2: Clone> Into<T1> for T2 {
fn into0(&self) -> T1 {
T1::from0(self.clone())
}
}
#[derive(Debug)]
struct TypeA(i32);
// TypeA实现了From<i32>
// 于是i32自动实现了Into<TypeA>
impl From<i32> for TypeA {
fn from0(val: i32) -> Self {
TypeA(val)
}
}
let ta: TypeA = TypeA::from0(666);
println!("{:?}", ta);
let ta: TypeA = 666.into0();
println!("{:?}", ta);
}