我读了一本由出版社出版的书,书名是Beginning Rust - Get Started with Rust 2021 Edition

在其中一个代码示例中,作者没有详细解释它,也没有清楚地解释代码是如何工作的.下面是代码片段

/* In a 64-bit system, it prints:
16 16 16; 8 8 8
In a 32-bit system, it prints:
8 8 8; 4 4 4
*/
fn main() {
    use std::mem::*;
    let a: &str = "";
    let b: &str = "0123456789";
    let c: &str = "abcdè";
    print!("{} {} {}; ",
        size_of_val(&a),
        size_of_val(&b),
        size_of_val(&c));
    print!("{} {} {}",
        size_of_val(&&a),
        size_of_val(&&b),
        size_of_val(&&c));
}

我的问题是它是如何工作的,因为_val的大小是一个参考值,这是在&但是为什么会出现在输出上呢!语句中,作者在变量前加了另一个符号?除此之外,当我们只传递变量而不需要额外的符号时,比如size_of_val(a或b或c),我们得到的大小是针对a 0、b 10和c 6的,但是当我们传递变量时,比如size_of_val(&a或&b或&c),就像作者描述的主函数上面的注释一样,大小是16或8.第二次打印最后一次!语句(宏)中,作者放了双符号来获得引用的大小?它是如何工作的.只是不明白,因为我认为这会产生错误,因为大小只接受一个参考,但在打印!宏有另一个和,第二个宏有双和...

推荐答案

size_of_val()函数是declared as follows:

pub fn size_of_val<T>(val: &T) -> usize
where
    T: ?Sized, 

这意味着:给定任何类型T(?Sized约束意味着"really任何类型,甚至没有大小的类型"),我们将引用T并返回usize.

让我们以a为例(bc是相同的).

当我们计算size_of_val(a)时,编译器知道a的类型是&str,因此它推断泛型参数是str(没有引用),因此完整调用是size_of_val::<str>(a /* &str */),这与签名匹配:我们给出&str代表T == str.

str号的尺寸是多少?str实际上是一个连续的字节序列,将字符串编码为UTF-8.a包含"",空字符串,当然是零字节长.所以size_of_val()返回0.对于b,有10个ASCII字符,每个字符都是一个字节长的UTF8编码字符,所以它们加起来有10个字节长.C包含4个ASCII字符(abcd),即4个字节,以及一个Unicode字符(è),两个字节宽,编码为\xC3\xA8(十进制为195和168).所以总长度是六个字节.

当我们计算size_of_val(&a)时会发生什么?&a&&str,因为a&str,所以编译器推断T&str.&str的大小是恒定的,并且始终是指针大小的两倍:这是因为&str,即指向str的指针,应该包括数据地址和长度.在64位平台上,这是16(8*2);在32位数字上是8(4*2).这被称为fat pointer,也就是一个指针,除了地址之外,它还携带额外的元数据(请注意,长度的两倍不是guaranteed,所以不要依赖它,但实际上是guaranteed).

当我们计算size_of_val(&&a)时,&&a的类型是&&&str,所以T被推断为&&str.&str(指向str的指针)是一个胖指针,意味着它的大小是原来的两倍,而指向胖指针的指针是一个普通的瘦指针(与胖指针相反:一个只携带地址的指针,没有任何额外的元数据),意味着它是一个机器字大小.因此,64位平台为8字节,32位平台为4字节.

Rust相关问答推荐

PyReadonlyArray2到Vec T<>

如何为rust trait边界指定多种可能性

是否可以在不切换到下一个位置的情况下获得迭代器值:

如果死 struct 实现了/派生了一些特征,为什么Rust会停止检测它们?

如何在函数中返回自定义字符串引用?

为什么我需要 to_string 函数的参考?

是否可以在不直接重复的情况下为许多特定类型实现一个函数?

如何限制 GtkColumnView 行数

为什么这个闭包没有实现Fn?

Rust编译器通过哪些规则来确保锁被释放?

Rust 中的 Option as_ref 和 as_deref 有什么不同

pyO3 和 Panics

一个函数调用会产生双重borrow 错误,而另一个则不会

如何使用泛型满足 tokio 异步任务中的生命周期界限

哪些特征通过 `Deref` 而哪些不通过?

没有分号的返回表达式的性能是否比使用返回更好?在Rust ?

使用 HashMap 条目时如何避免字符串键的短暂克隆?

Rust - 在线程之间不安全地共享没有互斥量的可变数据

在 Rust 中组合特征的不同方法是否等效?

在 macro_rules 中转义 $ 美元符号