我正在尝试围绕std::<T>::from_str_radix
构建一个通用包装器。根据文档,from_str_radix
返回Result<T, ParseIntError>
。但
fn foo<T: num_traits::Num>() -> Result<T, std::num::ParseIntError> {
T::from_str_radix("4242", 10)
}
不会编译:
另一方面,这
fn main() {
let x: Result<u8, std::num::ParseIntError> = foo();
println!("{:?}", x);
}
fn foo<T: num_traits::Num>() -> Result<T, <T as num_traits::Num>::FromStrRadixErr> {
T::from_str_radix("4242", 10)
}
编译良好并打印预期结果
在我看来,这两种情况都是一样的,但显然我是错的。有人可以向我解释差异并为我提供解决方案吗?
最佳答案
这是不可能的。某些错误(例如 io::Error
)使您可以创建带有导致错误的实例,因此您可以创建包含另一个错误的错误。如果ParseIntError
具有此类功能,则可以创建由ParseIntError
错误引起的FromStrRadixErr
,但ParseIntError
则不然。
这段代码:
fn foo<T: num_traits::Num>() -> Result<T, std::num::ParseIntError> {
T::from_str_radix("4242", 10)
}
无法编译,因为返回的
T::from_str_radix
类型是Result<T, FromStrRadixErr>
而不是Result<T, ParseIntError>
。将返回类型(如您所做的那样)更改为Result<T, FromStrRadixErr>
可以解决此问题。这段代码:
fn main() {
let x: Result<u8, std::num::ParseIntError> = foo();
println!("{:?}", x);
}
fn foo<T: num_traits::Num>() -> Result<T, <T as num_traits::Num>::FromStrRadixErr> {
T::from_str_radix("4242", 10)
}
可以正常编译,因为
Num
的u8
trait实现defines FromStrRadixErr = ParseIntError
。如果将
u8
更改为f32
:let x: Result<f32, std::num::ParseIntError> = foo();
它无法编译。
Num
defines f32
和FromStrRadixErr = ParseFloatError
的ParseFloatError
实现不是ParseIntError
的原因。您说过您正在尝试围绕
std::<T>::from_str_radix
构建一个通用包装器,但是您的示例在T::from_str_radix
中使用了T: Num
,因此您正在尝试围绕Num::from_str_radix
编写包装器。一种选择是直接使用
Num
和FromStrRadixErr
而不是创建包装器,最后Num
是包装器。也许您想将包装器限制为原始整数,并使用
ParseIntError
。在这种情况下,您可以添加限制FromStrRadixErr = ParseIntError
:fn foo<T>() -> Result<T, std::num::ParseIntError>
where T: num_traits::Num<FromStrRadixErr = std::num::ParseIntError>,
{
T::from_str_radix("4242", 10)
}