gpt4 book ai didi

macros - 类型推断的奇怪宏行为

转载 作者:行者123 更新时间:2023-11-29 08:35:52 28 4
gpt4 key购买 nike

我正在尝试理解宏并利用一个简单的宏来创建类似于 vec! 的 HashMap 。出于某种原因,如果我将 String 转换为宏内的 &str 它似乎不起作用。

macro_rules! hashmap {
($( $key: expr => $val: expr ),*) => {{
let mut map = ::std::collections::HashMap::new();
$( map.insert($key.clone(), $val.clone()); )*
map
}}
}

fn works(){
let value1 = 5;
let value1str: &str = &value1.to_string();
let h = hashmap!["key0" => "value0"
, "key1" => value1str];
println!("{:?}", h);
}

// fn does_not_work(){
// let value1 = 5;
// let h = hashmap!["key0" => "value0"
// , "key1" => &value1.to_string()];
// println!("{:?}", h);
// }

fn main(){
works();
//does_not_work();
}

Example on playpen

最佳答案

这是您的 works() 函数的有效主体:

fn works(){
let value1 = 5;
let value1str: &str = &value1.to_string();
let h = {
let mut map = HashMap::new();
map.insert("key0".clone(), "value0".clone());
map.insert("key1".clone(), value1str.clone());
map
};
println!("{:?}", h);
}

还有这一个 does_not_work():

fn does_not_work(){
let value1 = 5;
let h = {
let mut map = HashMap::new();
map.insert("key0".clone(), "value0".clone());
map.insert("key1".clone(), (&value1.to_string()).clone());
map
};
println!("{:?}", h);
}

当在 &str 上调用 clone() 时,它只是一个简单的按字节复制的胖指针(两个指针大小的数字):共享引用总是Copy;当然,克隆的引用也与原始引用具有相同的生命周期。这在 works() 中是可以的,因为那里使用的三个字符串切片指向静态内存,因为它们是字符串文字,第四个指向一个临时局部变量,它一直存在到函数结束:

let value1str: &str = &value1.to_string();
// is in fact equivalent to
let temporary = value1.to_string();
let value1str: &str = &temporary;

因为这个临时比散列映射存在的时间更长,所以可以将对它的引用存储在这个散列映射中:映射首先被销毁并且永远没有机会持有悬空引用。

但是,在第二种情况下,clone() 是在 &String 类型的值上调用的,因为 &s 如果 s : String 仅当编译器知道 &str 应该是目标类型时才会给你 &str ,而事实并非如此,因为 &value1.to_string () 之后传递给 clone()。当在 &String 上调用 clone() 时,它自然会委托(delegate)给 impl Clone for String,它只是制作另一个拥有的字符串副本,给你字符串。这反过来会给你一个类型不匹配的错误:

<anon>:20:34: 4:50 error: mismatched types:
expected `&str`,
found `collections::string::String`
(expected &-ptr,
found struct `collections::string::String`) [E0308]

有一种方法可以解决这个问题——您可以直接从 &String 中询问 &str ,例如明确再借:

&*value1.to_string()

但是,现在又会出现另一个问题。 value1.to_string() 返回的任何临时值仅在使用它的表达式中有效:

map.insert("key1".clone(), (&*value1.to_string()).clone());
// is roughly equivalent to
{
let temporary = value1.to_string();
map.insert("key1".clone(), (&*temporary).clone());
} // these braces are important!

您可以看到 temporary 会在 insert() 调用完成后立即被销毁,插入的引用将变为悬挂引用。 Rust 通过编译器错误来防止这种情况。

关于macros - 类型推断的奇怪宏行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33283763/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com