vector使用into_iter会发生所有权转移,但在下面这个例子里,teams.into_iter()之后,teams还能使用;
反而使用teams.iter()这种引用item的方式,会报错;这就有点奇怪了
use std::collections::HashMap;
fn main() {
let teams = [
("Chinese Team", 100),
("American Team", 10),
("France Team", 50),
];
let mut teams_map1 = HashMap::new();
for team in &teams {
teams_map1.insert(team.0, team.1);
}
let teams_map2 = teams.into_iter().collect();
//let teams_map2 =teams.iter().cloned().collect();//这样可行
//错误:
//HashMap<&str, i32> cannot be built from std::iter::Iterator<Item=&(&str, i32)>
//let teams_map2 =teams.iter().collect();
assert_eq!(teams_map1, teams_map2);
println!("Success! {:#?}",teams)
}
1
共 12 条评论, 1 页
评论区
写评论感谢大佬 .
--
👇
苦瓜小仔: > 入参是string情况下应该报错的,而rust自动加了一个引用,避免错误
嗯。这种自动引用和自动解引用只发生在 reciever type 上,即
self/&self/&mut self
这三种。而且任何时候,方法和函数签名的所有参数最终必须严格匹配类型。所以某些增加人体工程性的规则,比如 reciever type 上自动(解)引用、其他参数的 coercion,则发生在查找实现的过程中 。
Clone::clone
是&T -> T
的,其方法定义就是那样fn(&T) -> T
。而T -> T
意味着fn(T) -> T
。嗯。这种自动引用和自动解引用只发生在 reciever type 上,即
self/&self/&mut self
这三种。而且任何时候,方法和函数签名的所有参数最终必须严格匹配类型。所以某些增加人体工程性的规则,比如 reciever type 上自动(解)引用、其他参数的 coercion,则发生在查找实现的过程中 。
Clone::clone
是&T -> T
的,其方法定义就是那样fn(&T) -> T
。而T -> T
意味着fn(T) -> T
。感谢感谢,理解您的意思了; 因为&(&str, u8).clone 天然match了clone(&self) -> Self定义所以,就直接调用; 而String.clone,string无法匹配到&self,因此编译器自动加了一个&变成&string后match到clone(&self),才调用;
针对这两个类型的clone(&self) -> Self定义可以理解为下面函数的定义:
String::clone(&string)->String
// 入参是string情况下应该报错的,而rust自动加了一个引用,避免错误(&str,u8)::clone(&(&str,u8))->(&str,u8)
//入参是&(&str,u8),正好匹配了函数定义clone本身定义就是&T->T,但是因为初学时候用string和vec的clone次数太多,误以为clone是T->T的刻板印象;
再次感谢大佬!
我已经说过了,分析 val.clone() 的前提是 自动引用和解引用的方法调用规则。
即 Rust 查找 candidate receiver type 的顺序:
你还可以阅读和理解一下 这个帖子/例子,回答者 @vague 是我。
感谢大佬解惑,觉得距离真相更近一步了!
对照clone函数的定义,我还有一个疑惑; let t1: &(&str, u8) = &("", 1); let t2: (&str, u8) = t1.clone(); //
<(&str, u8) as Clone>::clone(&(&str, u8)) -> (&str, u8)
let t2: (&str, u8) = t1.clone(); //为什么不是<&(&str, u8) as Clone>::clone(&(&(&str, u8))) -> &(&str, u8)
呢?是因为(&str, u8)属于一种类型,而&(&str, u8)不是一种类型吗?
加了一个引用符号类型应该改变了吧?为什么不是&(&str, u8)去套泛型定义:
<T as Clone>::clone(&T) -> T
呢你混淆了
.clone
和.cloned
。 playgroundRust 是静态语言,每个方法调用都是明确被定义的,所有类型都是十分明确的。
Rust 的 Clone trait 定义如下:
分析调用方法,总是应该解糖,弄清楚每个参数的类型是什么。
对于
T: Clone
,其实例 t 通过t.clone()
得到类型为T
的值。.clone()
方法解糖为<T as Clone>::clone(&T) -> T
。但分析
x.clone()
的前提是 自动引用和解引用的方法调用规则。弄清楚规则是每个 Rust 新手的必经之路,因为这是隐式发生的而且很重要(不然你永远不知道如何分析调用哪个方法、怎么调用方法,所以你只观察到 a 与 b 通过.clone()
类型相同, t1 与 t2 类型不同)。a 的类型为 String, String 实现了 Clone,而
.clone()
方法需要&String
,Rust 自动添加引用,然后调用<String as Clone>::clone(&String) -> String
,得到 b,b 的类型为 String。我可能猜到了为什么&a.clone 和a.clone差异,因为&a本身不具有clone方法,编译器先解引用后再尝试clone,于是出现了clone后&T变T
--
👇
wangshankun: 又测了下string和vec的clone,clone出来的类型和原来一样; &(&str, u8)这个类型不一样 https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6cf94591e046c43c209bdd4d5ebe03f1
又测了下string和vec的clone,clone出来的类型和原来一样; &(&str, u8)这个类型不一样 https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6cf94591e046c43c209bdd4d5ebe03f1
感谢,
苦瓜小仔
大佬详细解惑!我看到了错误日志:想一想自己实现一个
FromIterator<&(K, V)>
是不是有点太麻烦了;另外,不知道cloned函数能把&T变成T,一直以为默认cloned出来应该和原类型保持一样;于是找到文档真是这样子: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.cloned
rust clone真不能想当然了(;
再次感谢大佬详细解惑!
是因为(&str, {integer}) 都是基础类型,默认可以copy吧?
--
👇
Grobycn:
into_iter()
之后还能用是因为实现了Copy
报错的哪一行是因为类型不匹配
into_iter()
之后还能用是因为实现了Copy
报错的哪一行是因为类型不匹配
如果你有认真阅读编译器给你的错误信息的话,就不会觉得奇怪:
teams.iter()
的类型是std::iter::Iterator<Item=&(&str, {integer})>
HashMap<&str, {integer}>
只实现了FromIterator<(K, V)>
,而没有实现FromIterator<&(&str, {integer})>
&(&str, {integer})
元素的迭代器中生成HashMap<&str, {integer}>
teams.iter().cloned()
就是把元素的类型从&(&str, {integer})
转化成(&str, {integer})
;所以你还可以使用teams.iter().copied()
、.map(|&t| t)
、.map(|t| *t)
等playground