Rust基础-关于trait之四-不得不说一下rust fat point

这张图相信C++的同学非常熟悉了,不就是继承、多态 、虚函数、balabala嘛,是的没错。

那么rust是什么布局呢?

它看起来下下面这样子所谓的fat point

有啥好处呢?

1、可以为已有类型实现 trait(比如 blanket implementations)

2、调用虚表中的函数时,只需要引用一次,而在 C++ 中,需要两次。

以下代码是为了深入了解一下关于fat point的机制,

use std::mem::transmute;
use std::fmt::{Debug, Formatter, Error};

struct Fmtfn<'a, T: 'a>(&'a fn(&T, &mut Formatter) -> Result<(), Error>, &'a T);

impl<'a, T> Debug for Fmtfn<'a, T> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        println!("self.0: {:?}", self.0 as *const _ as usize);
        println!("self.1: {:?}", self.1 as *const _ as usize);
        println!("f: {:?}", f as *const _ as usize);
        self.0(self.1, f)
    }
}

fn main() {
     let v: Vec<u64> = vec![1, 2, 3, 4];
     let a: &Vec<u64> = &v;
     let b: &[u64] = &v;
     let c: &dyn Debug = &v;

     let (_, vtable) = unsafe { transmute::<_, (usize, usize)>(c) };
     let fmt3 = unsafe { &*((vtable as *const fn(&Vec<u64>, &mut Formatter) -> Result<(), Error>).offset(3)) };
     let fmt0= unsafe { &*((vtable as *const fn(&Vec<u64>, &mut Formatter) -> Result<(), Error>).offset(0)) };
     let fmt1= unsafe { &*((vtable as *const fn(&Vec<u64>, &mut Formatter) -> Result<(), Error>).offset(1)) };
     let fmt2= unsafe { &*((vtable as *const fn(&Vec<u64>, &mut Formatter) -> Result<(), Error>).offset(2)) };
     println!("a: {}", a as *const _ as usize);
     println!("b: {:?}", unsafe { transmute::<_, (usize, usize)>(b) });
     println!("c: {:?}", unsafe { transmute::<_, (usize, usize)>(c) });
     println!("fmt0: {}", fmt0 as *const _ as usize);
     println!("fmt1: {}", fmt1 as *const _ as usize);
     println!("fmt2: {}", fmt2 as *const _ as usize);
     println!("fmt3: {}", fmt3 as *const _ as usize);
     println!("{:?}", unsafe { &*(vtable as *const [usize; 3]) });
     println!("{:?}", Fmtfn(fmt3, &v));
}

输出:

 a和c的第一个指针的地址是一样的,而b不一样,

那么断点看一下:

显而易见,ptr指向的地址就是dataptr,指向了数组的第一个对象,而b的地址很显然是Vec转换为切片后的地址,因为当let b: &[u64] = &v;时会调用Vec的Deref trait(rust/src/liballoc/vec.rs)如下图所示:

 那么dataptr有了。接下去找vtable里面有什么。

接下来看输出:

c的第二个地址就是vtable的入口地址和fmt0一样,后面fmt0,fmt1,fmt2,fmt3,每个len是8字节。

似乎vtable里应该只有fn fmt()这个函数,其他是啥?

先看断点的截图:

 很明显fmt0是指向的core::ptr::drop_in_place,fmt3是指向的fmt,为什么呢?答案在rust/src/librustc_codegen_llvm/meth.rs里,下图 

所以在任何方法之前的 vtable 中就有三个值(大小usize),而第四个才是自定义的trait。

所以fmt3和函数内的self.0才是指向fn fmt的指针。下一篇介绍trait 的upcast、downcast和compose了。

相关文章

Rust基础-关于trait之一_DarcyZ_SSM的博客-CSDN博客

Rust基础-关于trait之二_DarcyZ_SSM的博客-CSDN博客

Rust基础-关于trait之三_DarcyZ_SSM的博客-CSDN博客

Rust基础-关于trait之五_DarcyZ_SSM的博客-CSDN博客

Rust基础-关于trait之六,动态派发和静态派发的区别

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值