我如何为这个 Rust 特性使用相同的默认实现
How can I use the same default implementation for this Rust trait
我想实现一个允许分配泛型类型的特征。到目前为止,我已经针对 u32
和 String
类型进行了测试:
trait Test {
fn test(&self, input: &str) -> Self;
}
impl Test for String {
fn test(&self, input: &str) -> Self {
input.parse().unwrap()
}
}
impl Test for u32 {
fn test(&self, input: &str) -> Self {
input.parse().unwrap()
}
}
fn main() {
let mut var = 0u32;
let mut st = String::default();
var = var.test("12345678");
st = st.test("Text");
println!("{}, {}", var, st);
}
我知道这段代码并不完美,我应该使用 Result
return 而不是解包,但请把它放在一边,因为这是一个简单的例子。 u32
和 String
的实现完全相同,所以我想对两者都使用默认实现,而不是复制和粘贴代码。我试过使用一个,但由于 returned 类型 Self
两者不同,编译器无法确定类型大小和错误。
在这种情况下如何编写默认实现?
默认实现
默认实现需要 Self
的以下界限:
Self: Sized
因为Self
是函数返回的,会被放到调用者的栈中
Self: FromStr
因为您在 input
上调用 parse()
并期望它产生 Self
类型的值
<Self as FromStr>::Err: Debug
因为当你 unwrap
一个潜在的错误并且程序 panic 时,Rust 希望能够打印错误信息,这需要错误类型来实现 Debug
完整实施:
use std::fmt::Debug;
use std::str::FromStr;
trait Test {
fn test(&self, input: &str) -> Self
where
Self: Sized + FromStr,
<Self as FromStr>::Err: Debug,
{
input.parse().unwrap()
}
}
impl Test for String {}
impl Test for u32 {}
fn main() {
let mut var = 0u32;
let mut st = String::default();
var = var.test("12345678");
st = st.test("Text");
println!("{}, {}", var, st);
}
通用实现
通用的一揽子实现也是可能的,您可以在其中自动为满足特征边界的所有类型提供 Test
的实现:
use std::fmt::Debug;
use std::str::FromStr;
trait Test {
fn test(&self, input: &str) -> Self;
}
impl<T> Test for T
where
T: Sized + FromStr,
<T as FromStr>::Err: Debug,
{
fn test(&self, input: &str) -> Self {
input.parse().unwrap()
}
}
fn main() {
let mut var = 0u32;
let mut st = String::default();
var = var.test("12345678");
st = st.test("Text");
println!("{}, {}", var, st);
}
宏实现
此实现类似于默认实现,允许您选择哪些类型获得实现,但它也类似于通用实现,因为它不需要您使用任何额外的修改特征方法签名特征界限:
trait Test {
fn test(&self, input: &str) -> Self;
}
macro_rules! impl_Test_for {
($t:ty) => {
impl Test for $t {
fn test(&self, input: &str) -> Self {
input.parse().unwrap()
}
}
}
}
impl_Test_for!(u32);
impl_Test_for!(String);
fn main() {
let mut var = 0u32;
let mut st = String::default();
var = var.test("12345678");
st = st.test("Text");
println!("{}, {}", var, st);
}
主要区别
这 3 种方法之间的主要区别:
- 默认实现使方法签名固有的特征边界,因此所有类型 impl
Test
必须是大小,并有一个具有可调试错误类型的 FromStr
impl。
- 默认实现允许您有选择地选择哪些类型获得
Test
实现。
- 通用实现不会向特征方法的签名添加任何特征边界,因此更多种类的类型可能会实现该特征。
- 泛型实现会自动为满足边界的所有类型实现特征,如果有一些您不希望实现特征的类型,您不能有选择地“选择退出”泛型实现。
- 宏实现不需要使用额外的特征边界修改特征方法签名,并允许您有选择地选择实现的类型。
- 宏实现是一个宏,并且具有作为宏的所有缺点:更难阅读、编写、维护、增加编译时间,而且宏对静态代码分析器来说本质上是不透明的,这使得它更难轻松地输入-检查你的代码。
我想实现一个允许分配泛型类型的特征。到目前为止,我已经针对 u32
和 String
类型进行了测试:
trait Test {
fn test(&self, input: &str) -> Self;
}
impl Test for String {
fn test(&self, input: &str) -> Self {
input.parse().unwrap()
}
}
impl Test for u32 {
fn test(&self, input: &str) -> Self {
input.parse().unwrap()
}
}
fn main() {
let mut var = 0u32;
let mut st = String::default();
var = var.test("12345678");
st = st.test("Text");
println!("{}, {}", var, st);
}
我知道这段代码并不完美,我应该使用 Result
return 而不是解包,但请把它放在一边,因为这是一个简单的例子。 u32
和 String
的实现完全相同,所以我想对两者都使用默认实现,而不是复制和粘贴代码。我试过使用一个,但由于 returned 类型 Self
两者不同,编译器无法确定类型大小和错误。
在这种情况下如何编写默认实现?
默认实现
默认实现需要 Self
的以下界限:
Self: Sized
因为Self
是函数返回的,会被放到调用者的栈中Self: FromStr
因为您在input
上调用parse()
并期望它产生Self
类型的值
<Self as FromStr>::Err: Debug
因为当你unwrap
一个潜在的错误并且程序 panic 时,Rust 希望能够打印错误信息,这需要错误类型来实现Debug
完整实施:
use std::fmt::Debug;
use std::str::FromStr;
trait Test {
fn test(&self, input: &str) -> Self
where
Self: Sized + FromStr,
<Self as FromStr>::Err: Debug,
{
input.parse().unwrap()
}
}
impl Test for String {}
impl Test for u32 {}
fn main() {
let mut var = 0u32;
let mut st = String::default();
var = var.test("12345678");
st = st.test("Text");
println!("{}, {}", var, st);
}
通用实现
通用的一揽子实现也是可能的,您可以在其中自动为满足特征边界的所有类型提供 Test
的实现:
use std::fmt::Debug;
use std::str::FromStr;
trait Test {
fn test(&self, input: &str) -> Self;
}
impl<T> Test for T
where
T: Sized + FromStr,
<T as FromStr>::Err: Debug,
{
fn test(&self, input: &str) -> Self {
input.parse().unwrap()
}
}
fn main() {
let mut var = 0u32;
let mut st = String::default();
var = var.test("12345678");
st = st.test("Text");
println!("{}, {}", var, st);
}
宏实现
此实现类似于默认实现,允许您选择哪些类型获得实现,但它也类似于通用实现,因为它不需要您使用任何额外的修改特征方法签名特征界限:
trait Test {
fn test(&self, input: &str) -> Self;
}
macro_rules! impl_Test_for {
($t:ty) => {
impl Test for $t {
fn test(&self, input: &str) -> Self {
input.parse().unwrap()
}
}
}
}
impl_Test_for!(u32);
impl_Test_for!(String);
fn main() {
let mut var = 0u32;
let mut st = String::default();
var = var.test("12345678");
st = st.test("Text");
println!("{}, {}", var, st);
}
主要区别
这 3 种方法之间的主要区别:
- 默认实现使方法签名固有的特征边界,因此所有类型 impl
Test
必须是大小,并有一个具有可调试错误类型的FromStr
impl。 - 默认实现允许您有选择地选择哪些类型获得
Test
实现。 - 通用实现不会向特征方法的签名添加任何特征边界,因此更多种类的类型可能会实现该特征。
- 泛型实现会自动为满足边界的所有类型实现特征,如果有一些您不希望实现特征的类型,您不能有选择地“选择退出”泛型实现。
- 宏实现不需要使用额外的特征边界修改特征方法签名,并允许您有选择地选择实现的类型。
- 宏实现是一个宏,并且具有作为宏的所有缺点:更难阅读、编写、维护、增加编译时间,而且宏对静态代码分析器来说本质上是不透明的,这使得它更难轻松地输入-检查你的代码。