如何声明支持移动与借用的Into<T>超特性并修复编译错误?
问题:让Trait同时支持移动和借用语义的Into转换
想要声明一个Trait T,使其同时支持两种Into<R>转换:
- 接收
T类型(移动语义)的into方法:fn into(self) -> R; - 接收
&T类型(借用语义)的into方法:fn into(&self) -> R;
以下是我写的代码及编译错误:
用户代码
use strum::IntoStaticStr; trait EnumIntoStaticStr: Into<&'static str> {} impl<T: Into<&'static str>> EnumIntoStaticStr for T {} #[derive(IntoStaticStr)] enum MyEnum { Foo, Bar(String), } fn main() { let v = MyEnum::Foo; let str = borrow_into_str(&v); drop(v); println!("{}", str); } fn move_into_str(v: impl EnumIntoStaticStr) -> &'static str { v.into() } fn borrow_into_str(v: &impl EnumIntoStaticStr) -> &'static str { v.into() }
编译错误
error[E0277]: the trait bound `&str: From<&impl EnumIntoStaticStr>` is not satisfied --> src/main.rs:24:7 | 24 | v.into() | ^^^^ the trait `From<&impl EnumIntoStaticStr>` is not implemented for `&str` | = note: required for `&impl EnumIntoStaticStr` to implement `Into<&str>` help: consider dereferencing here | 24 | (*v).into() | ++ + For more information about this error, try `rustc --explain E0277`.
修复方案
错误原因
当前的EnumIntoStaticStr只要求类型自身实现Into<&'static str>,但对于&impl EnumIntoStaticStr这种引用类型,Rust不会自动为其实现Into<R>——哪怕原类型已经满足约束,引用类型的Into实现需要单独声明。
方法一:修改自定义Trait的约束
让EnumIntoStaticStr同时要求类型自身和它的引用都实现Into<&'static str>:
use strum::IntoStaticStr; // 约束Self和&Self都能转换为&'static str trait EnumIntoStaticStr: Into<&'static str> where &Self: Into<&'static str> {} // 实现Trait时,确保T和&T都满足Into约束 impl<T> EnumIntoStaticStr for T where T: Into<&'static str>, &T: Into<&'static str> {} #[derive(IntoStaticStr)] enum MyEnum { Foo, Bar(String), } fn main() { let v = MyEnum::Foo; let str = borrow_into_str(&v); drop(v); println!("{}", str); } fn move_into_str(v: impl EnumIntoStaticStr) -> &'static str { v.into() } fn borrow_into_str(v: &impl EnumIntoStaticStr) -> &'static str { v.into() }
strum的IntoStaticStr宏已经自动为MyEnum和&MyEnum都实现了Into<&'static str>,修改后Trait的双重约束被满足,代码可以正常编译。
方法二:直接使用Into约束(更简洁)
如果不需要自定义Trait封装,直接在函数参数里用impl Into<&'static str>即可——因为&MyEnum本身已经通过宏实现了Into<&'static str>:
use strum::IntoStaticStr; #[derive(IntoStaticStr)] enum MyEnum { Foo, Bar(String), } fn main() { let v = MyEnum::Foo; let str = borrow_into_str(&v); drop(v); println!("{}", str); } fn move_into_str(v: impl Into<&'static str>) -> &'static str { v.into() } fn borrow_into_str(v: impl Into<&'static str>) -> &'static str { v.into() }
这种写法省去了自定义Trait的冗余,更符合Rust的简洁风格。
内容的提问来源于stack exchange,提问作者Bitcoin Eagle
相关产品推荐
相关产品推荐

