< 返回版块

ZZG 发表于 2023-07-12 15:57

先说下我的理解,如果有误感谢大佬们指出:

  1. [T; N]类似于数组的概念,长度在编译期可知,且不会变化,长度N也是类型的一部分。[T; N]满足Sized trait

  2. [T]和[T; N]的区别在于[T]的长度在编译期不可知,不满足Sized trait。因此一般都使用&[T]来指向[T],这个指针除了有数据的地址,还保存有[T]的长度信息,因此被称为胖指针fat pointer

现在有这样一段代码

fn main() {
    let array: [u8; 5] = [1, 2, 3, 4, 5];
    let slice: &[u8] = &array[..];


    println!("Array pointer size {}", size_of_val(&&array));  // 8
    println!("Slice pointer size {}", size_of_val(&slice));   // 16

    println!("Array length {}", array.len());                 // 5
    println!("Slice length {}", slice.len());                 // 5
}

Array的指针大小是8 bytes,Slice则是16 bytes,似乎正好满足Slice是fat pointer的事实。

接下来问题来了,发现array.len()和slice.len()都调用的是下面的代码

impl<T> [T] {

    pub const fn len(&self) -> usize {
        ptr::metadata(self)
    }
}

array和slice都是从自己的指针中取metadata,那么两个都是胖指针?那为什么打印Array指针大小为8而不是16呢?

还是说我计算Array指针大小的写法是错误的?

求大佬们解答一下,谢谢~

评论区

写评论
作者 ZZG 2023-07-12 16:48

感谢感谢😀,没人教的话我怎么也不会想到是这个原因

--
👇
aj3n: https://doc.rust-lang.org/stable/reference/type-coercions.html#unsized-coercions

你关于指针长度的理解没有问题. 两种写法都调用的<[T]>::len主要是因为调用array.len()的时候发生了unsized-coercion, 会把&[T;N]隐式转换成&[T], 参考上面的链接; 我感觉这个不是很重要标准库实现技巧,以后对关注到类似的隐式转换简单参考下就好;

Wuyan 2023-07-12 16:45

个人理解array是相当于下面一个C语言结构体数据

struct Array{
    u8 index0;
    u8 index1;
    u8 index2;
    u8 index3;
    u8 index4;
};

&array相当于下面一个C语言结构体数据:

struct ArrayRef{
    struct Array*ptr;
    usize len;
}

&&array相当于下面一个C语言ArrayRef的指针:&&array=&ArrayRef

所以size_of_val(&&array)是返回当前平台存储的指针大小,size_of_val(&array)返回ArrayRef结构体大小

aj3n 2023-07-12 16:23

https://doc.rust-lang.org/stable/reference/type-coercions.html#unsized-coercions

你关于指针长度的理解没有问题. 两种写法都调用的<[T]>::len主要是因为调用array.len()的时候发生了unsized-coercion, 会把&[T;N]隐式转换成&[T], 参考上面的链接; 我感觉这个不是很重要标准库实现技巧,以后对关注到类似的隐式转换简单参考下就好;

1 共 3 条评论, 1 页