传递给 size_of_val 的双符号如何工作?
How does double ampersands passed to size_of_val work?
我读了 Apress 出版的一本书 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));
}
我的问题是它是如何工作的,因为 size_of_val 需要引用并且这是在 &str 的声明中完成的。但是怎么打印出来!声明,作者在变量前放了另一个符号?除此之外,当我们传递变量时没有额外的符号,例如 size_of_val(a or b or c),我们得到的大小是 a 0,b 10 和 c 6,但是当我们传递带有符号的变量,例如size_of_val(&a or &b or &c),然后就像作者描述的主要功能上面的注释一样,大小为16 16 16或8 8 8。最后是第二次打印!语句(宏),作者把双&号放在参考的大小?它是如何工作的。只是不要明白,因为我认为这会产生错误,因为 size_of_val 只接受一个参考,但随后出现在打印中!宏有另一个和号,第二个宏有双和号...
size_of_val()
函数是declared as follows:
pub fn size_of_val<T>(val: &T) -> usize
where
T: ?Sized,
这意味着:给定任何类型 T
(?Sized
约束意味着“真的任何类型,甚至是未定型的”),我们取一个参考T
并返回一个 usize
.
以a
为例(b
和c
是一样的)
当我们评估 size_of_val(a)
时,编译器知道 a
具有类型 &str
,因此它推断泛型参数为 str
(没有引用) ,所以完整的调用是 size_of_val::<str>(a /* &str */)
,它与签名匹配:我们为 T == str
.
给出 &str
str
的大小是多少? str
实际上是一个连续的字节序列,将字符串编码为UTF-8。 a
包含 ""
,空字符串,当然是零字节长。所以 size_of_val()
returns 0。对于 b
,有 10 个 ASCII 字符,每个都是一个字节长的 UTF8 编码,所以它们加起来有 10 个字节长。 C 包含 4 个 ASCII 字符 (abcd
),即四个字节和一个 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)。这称为 ,即除了地址之外还携带额外元数据的指针(请注意,保证 不会是长度的两倍,所以不要不依赖它,但实际上它是)。
当我们评估size_of_val(&&a)
时,&&a
的类型是&&&str
,所以T
被推断为&&str
。虽然 &str
(指向 str
的指针)是一个胖指针,这意味着它的大小增加了一倍,但指向胖指针的指针是一个普通的瘦指针(与胖指针相反:一个指针只携带地址,没有任何额外的元数据),这意味着它是一个机器字大小。所以 64 位平台为 8 个字节,32 位平台为 4 个字节。
我读了 Apress 出版的一本书 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));
}
我的问题是它是如何工作的,因为 size_of_val 需要引用并且这是在 &str 的声明中完成的。但是怎么打印出来!声明,作者在变量前放了另一个符号?除此之外,当我们传递变量时没有额外的符号,例如 size_of_val(a or b or c),我们得到的大小是 a 0,b 10 和 c 6,但是当我们传递带有符号的变量,例如size_of_val(&a or &b or &c),然后就像作者描述的主要功能上面的注释一样,大小为16 16 16或8 8 8。最后是第二次打印!语句(宏),作者把双&号放在参考的大小?它是如何工作的。只是不要明白,因为我认为这会产生错误,因为 size_of_val 只接受一个参考,但随后出现在打印中!宏有另一个和号,第二个宏有双和号...
size_of_val()
函数是declared as follows:
pub fn size_of_val<T>(val: &T) -> usize
where
T: ?Sized,
这意味着:给定任何类型 T
(?Sized
约束意味着“真的任何类型,甚至是未定型的”),我们取一个参考T
并返回一个 usize
.
以a
为例(b
和c
是一样的)
当我们评估 size_of_val(a)
时,编译器知道 a
具有类型 &str
,因此它推断泛型参数为 str
(没有引用) ,所以完整的调用是 size_of_val::<str>(a /* &str */)
,它与签名匹配:我们为 T == str
.
&str
str
的大小是多少? str
实际上是一个连续的字节序列,将字符串编码为UTF-8。 a
包含 ""
,空字符串,当然是零字节长。所以 size_of_val()
returns 0。对于 b
,有 10 个 ASCII 字符,每个都是一个字节长的 UTF8 编码,所以它们加起来有 10 个字节长。 C 包含 4 个 ASCII 字符 (abcd
),即四个字节和一个 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)。这称为
当我们评估size_of_val(&&a)
时,&&a
的类型是&&&str
,所以T
被推断为&&str
。虽然 &str
(指向 str
的指针)是一个胖指针,这意味着它的大小增加了一倍,但指向胖指针的指针是一个普通的瘦指针(与胖指针相反:一个指针只携带地址,没有任何额外的元数据),这意味着它是一个机器字大小。所以 64 位平台为 8 个字节,32 位平台为 4 个字节。