< 返回我的博客

爱国的张浩予 发表于 2021-07-21 07:30

Tags:smart-pointer,dereference,coercion

智能指针【去引用】强制转换计算公式

之前在github上看各个大神的rust代码,我经常会遇到

  • &str形参传递&String实参
  • &[T]形参传递&Vec<T>实参

的语言现象。不理解之(哎,我也是·席勒马虎·写代码),我都是见一个记一个、见一类记一类。这照实低效。最近在地铁上(最伟大的公众交通),仔细捋了捋Deref/DerefMutRust Docs,算是解惑了,且总结了如下的公式。没准也有助于你的参悟。

T: Deref<Target = U: ?Sized>,则有

  • T被视作有额外“能力”(即,成员方法)的U的引用。即,智能指针。
    • 公式:T -> &U
  • T执行【·显示·引用】操作*,得到的就是U
    • 公式推导:*T -> *(&U) -> U
  • T执行【·显示·引用】操作&,得到的就是&U
    • 公式推导:&T - 自动去引用 -> &(*T) -> &U
  • T实例上可直接访问到U上所有成员方法与成员字段,因为【·自动/隐式·去引用】。即,
    • 公式推导:T.u_member() - 自动去引用 -> (*T).u_member() -> U.u_member()

T: DerefMut<Target = U: ?Sized>,则有

  • T被视作有额外“能力”(即,成员方法)的U的可修改引用。即,智能指针。
    • 公式:T -> &mut U
  • T执行【·显示·引用】操作*,得到的就是mut U
    • 公式推导:*T -> *(&mut U) -> mut U
  • T执行【·显示·引用】操作&mut,得到的就是&mut U
    • 公式推导:&mut T - 自动去引用 -> &mut (*T) -> &mut (mut U) -> &mut U
  • T实例上可直接访问到U上所有成员方法与成员字段,因为【·自动/隐式·去引用】。即,
    • 公式推导:T.u_member() - 自动去引用 -> (*T).u_member() -> (mut U).u_member()

至于【自动·去·引用】触发时机的描述,那就得再写另一篇笔记来分享了。一次只填一个小坑。

评论区

写评论
c5soft 2023-03-17 15:25

好文! 总结成两句话:

在T上实现了Deref<Target = U: ?Sized>这个trait,就是赋予了通过T获得&U的能力, 用能力公式:“T -> &U”来表达,推导出实际用例:*T -> *(&U) -> U 与 &T -> &&U -> &U

在T上实现了DerefMut<Target = U: ?Sized>这个trait,就是赋予了通过T获得&mut U的能力, 用能力公式:“T -> &mut U”来表达,推导出实际用例:*T -> *(&mut U) -> mut U 与 &mut T -> &mut (&mut U) -> &mut U

use std::ops::{Deref, DerefMut};

#[derive(Debug,Clone,Copy)]
struct Dad<T> {
    pub child: T,
}


impl<T> Deref for Dad<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.child
    }
}

impl<T> DerefMut for Dad<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.child
    }
}

#[derive(Debug,Clone,Copy)]
pub struct Son<T> {
    pub age: T,
}


impl<T> Deref for Son<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.age
    }
}


fn main() {
    let mut a = Dad {
        child: Son { age: 10 },
    };

    println!("a is {a:?}");

    let b = &a;
    println!("b=&a -> b is {:?} ", b);
    let b = &a as &Son<i32>;
    println!("b=&a as &Child<i32> -> b is {b:?} ");

    let b = &mut a;
    b.child.age = 20;
    println!("b=&mut a;b.child.age=20 -> b is {b:?} ");
    b.age = 30;
    println!("b=&mut a;b.age=30 -> b is {b:?} ");

    let b = &mut a as &mut Son<i32>;
    b.age = 40;
    println!("b=&mut a as &mut Child<i32>;b.age=40 -> b is {b:?}");

    let c=&&a;
    println!("c=&&a -> c={c:?}");
    println!("c=&&a and c as &Son<i32> -> c is {:?}", c as &Son<i32>);
    println!("c=&&a -> c.age={:?}", c.age);
    let d=*c;
    println!("d=*c -> d is {d:?}");
    let d=**c;
    println!("d=**c -> d is {d:?}");
    let d=***c;
    println!("d=***c -> d is {d:?}");

    let d=****c; // if Son not impl Deref, here panic
    println!("d=****c -> d is {d:?}");


}

运行结果:

a is Dad { child: Son { age: 10 } }
b=&a -> b is Dad { child: Son { age: 10 } } 
b=&a as &Child<i32> -> b is Son { age: 10 }
b=&mut a;b.child.age=20 -> b is Dad { child: Son { age: 20 } }
b=&mut a;b.age=30 -> b is Dad { child: Son { age: 30 } }
b=&mut a as &mut Child<i32>;b.age=40 -> b is Son { age: 40 }
c=&&a -> c=Dad { child: Son { age: 40 } }
c=&&a and c as &Son<i32> -> c is Son { age: 40 }
c=&&a -> c.age=40
d=*c -> d is Dad { child: Son { age: 40 } }
d=**c -> d is Dad { child: Son { age: 40 } }
d=***c -> d is Son { age: 40 }
d=****c -> d is 40
1 共 1 条评论, 1 页