Rust HashMap 插入方法使用生成的字符串生成借用检查器错误

Rust HashMap insert method producing borrow-checker error with generated string

提问人:acctech007 提问时间:5/31/2023 更新时间:5/31/2023 访问量:54

问:

我正在尝试 Rust,但很难理解为什么编译器在终生问题上使我的代码失败。这是问题所在。

以下是使用货物工作区组织代码的方式。

.
├── Cargo.lock
├── Cargo.toml
├── README.md
├── collections
│   ├── Cargo.toml
│   └── src
└── utils
    ├── Cargo.toml
    └── src

我在 lib 中定义了一个函数,我从集合中调用它。generate_stringutils

/// defined in utils/src/lib.rs
pub fn generate_string (size: usize) -> String {
    Alphanumeric.sample_string(&mut rand::thread_rng(), size)
}

现在尝试从 collections/src/stone.rs 调用它

mod tets { 
   fn test_normalize_large_input() {
        let map_lenght = 50000;
        let err_message = "normalize handles large inputs.";
        let mut profile: HashMap<&str, f64> = HashMap::new();
        for _ in 0..map_lenght {
            let key: String = utils::generate_string(8);
            profile.insert(&key, 1.0); // this won't work
        }
        let got = normalize(&profile).unwrap();
        assert_eq!(got.len(), 1, "{}", err_message);
        assert!(got.contains_key("singleton"), "{}", err_message);
    }
}

我有一个编译问题。

    |
462 |             let key: String = utils::generate_string(8);
    |                 --- binding `key` declared here
463 |             profile.insert(&key, 1.0);
    |                            ^^^^ borrowed value does not live long enough
464 |         }
    |         - `key` dropped here while still borrowed

这是我不明白的。我看不出哪个变量或函数借用了变量。因为当我检查文档时,该方法没有借用密钥参数。keyinsertHashMap

问题是,1)什么是实际借款?如何在地图中插入返回 没有问题?keyutils::generate_string

我试图以这种方式克隆变量。我期望克隆会复制内存内容,以便密钥的生存期不再是问题。但它也不起作用。这次我又收到一个错误。keyprofile.insert(key.clone().as_str(), 1.0);

    |
463 |             profile.insert(key.clone().as_str(), 1.0);
    |             ---------------^^^^^^^^^^^---------------- temporary value is freed at the end of this statement
    |             |              |
    |             |              creates a temporary value which is freed while still in use
    |             borrow later used here
    |
    = note: consider using a `let` binding to create a longer lived value

实际上,我不想克隆变量。我确实尝试过这个,看看它会如何表现。

提前感谢您的帮助。

rust borrow-checker borrow

评论

2赞 PitaJ 5/31/2023
profile.insert(&key, 1.0);借用 as an .但是,它将在循环体的末尾被丢弃(解除分配,销毁)。这就是您收到错误的原因。改为 a。key&strkeyStringprofileHashMap<String, f64>
0赞 acctech007 5/31/2023
@PitaJ,我忘了提到规范化函数(normalize(&profile))将HashMap<&str,f64>作为参数。有什么方法可以在不重构规范化函数的情况下让它工作?
0赞 PitaJ 5/31/2023
函数从何而来?normalize
0赞 Masklinn 5/31/2023
有一种方法,但它非常复杂:您需要创建一个可以代表地图拥有(持有)所有实例的向量。这可以通过两个循环轻松完成,首先创建一个键向量,然后从借用中创建一个映射。但是,如果您需要在单个循环中执行此操作,则需要弄乱借用拆分,因为容器在具有未完成的借用(哈希映射的键)时不能发生突变(插入或替换值)key

答:

2赞 Masklinn 5/31/2023 #1

我看不出哪个变量或函数借用了变量键。因为 HashMap 的 insert 方法在我查看文档时没有借用键参数。

insert没有,但当你写的时候你会这样做

profile.insert(&key, 1.0); 

那是借来的。您不是在地图中插入,而是在插入对 的引用。keykey

因为 是循环作用域所拥有的,所以它在迭代结束时停止,因此引用是悬空的,这是非法的。keyString

您需要将地图设为 a,以便您可以在地图中移动,并且地图从那里开始拥有字符串。HashMap<String, f64>key

profile.insert(key.clone().as_str(), 1.0);

这只是同一问题的更复杂版本(实际上是一个更糟糕的问题)。 是一个临时的,它被放在语句的末尾(紧接在完成和返回之后),并且你插入了对该临时的引用,这是一个更短的借用。key.clone()insert

你真的应该仔细考虑阅读或重读 Rust 这本书,因为你在这里遇到了语言的绝对基础,这不会是一次有趣的体验。Rust 不是一种简单的语言,除非你有 C 或 C++ 的大师级知识,否则几乎不可能通过在编辑器中学习,有些概念是新颖的,没有非学术语言,并且尽管编译器试图提供帮助,但它会让你很难阻止,它不能为问题提供完整的指导。也许有一天,但不是现在,也不是很快。