为何Rust中&i32可与&&i32比较?两类场景差异解析
&T与&&T在泛型函数里可比较,直接写却报错? 问题场景
在如下泛型largest函数中,item > largest与item > &largest两个表达式均可正常编译:
use std::fmt::Display; fn largest<T>(list: &[T]) -> &T where T: PartialOrd + Display { let mut largest = &list[0]; for item in list.iter() { // item: &i32 // largest: &i32 // &largest: &&i32 if item > &largest { println!("item > &largest: {}", item > &largest); } if item > largest { println!("item > largest: {}", item > largest); largest = &item; } } &largest } fn main() { let number_list = vec![34, 50, 45]; let result = largest(&number_list); println!("The largest number is {}", result); }
但直接尝试比较&i32与&&i32时,却会收到错误提示:no implementation for {integer} < &{integer} and {integer} > &{integer}
对应的测试代码:
let a = 10; // i32 let b = &a; // &i32 let c = &b; // &&i32 println!("{}", b > c);
原因解释
核心差异来自Rust自动解引用规则在泛型与具体类型场景下的不同表现,结合PartialOrd trait的实现逻辑:
泛型函数中的自动解引用逻辑
在largest函数中,item是&T类型,&largest是&&T类型。由于我们给T绑定了PartialOrd约束,而Rust标准库会为所有实现PartialOrd的类型U,自动实现PartialOrd for &U、PartialOrd for &&U等多层引用类型的比较逻辑。
同时,泛型上下文里的编译器会主动尝试对操作数进行自动解引用,直到找到符合PartialOrd约束的合法类型组合。比如比较item > &largest时,编译器会自动将&&T解引用为&T,或者将&T解引用为T,最终转为同类型比较,而T本身实现了PartialOrd,因此可以正常编译。具体类型比较的限制
在b > c的代码中,b是&i32,c是&&i32。此时编译器不会主动进行多层隐式解引用——Rust的自动解引用规则在具体类型场景下会更保守,避免歧义。如果要让代码合法,需要显式解引用,比如写成b > *c,这样就能转为&i32与&i32的比较,符合PartialOrd的实现要求。
内容的提问来源于stack exchange,提问作者inmove shawn

