rust - 尽管有限制,Rust `cannot infer type`
问题描述
我想编写一段代码,它可以采用可复制类型的引用或拥有的值,并返回该类型的拥有版本。我已将类型推断的问题减少到以下代码,其中错误:
use std::borrow::Borrow;
fn copy<R, E>(val: E) -> R
where
R: Default + Copy,
E: Borrow<R>,
{
*val.borrow()
}
fn main() {
assert_eq!(6, copy(&6));
assert_eq!(6, copy(6));
assert_eq!(6.0, copy(&6.0));
assert!((6.0f64 - copy(&6.0f64)).abs() < 1e-6);
}
错误来自最后一个断言:
error[E0282]: type annotations needed
--> src/main.rs:15:13
|
15 | assert!((6.0f64 - copy(&6.0f64)).abs() < 1e-6);
| ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
|
= note: type must be known at this point
我唯一的假设是允许orSub
上的特征,如果不存在约束,那么最后一个副本的有效表达式将是,但是这是不允许的,因为没有实现。如果我们通过值传递它会起作用,大概是因为它限制为 be而不是两者之一。f64
f64
&f64
Default
copy::<&f64, &f64>(&6.0f64)
&f64
Default
f64
R
f64
我不清楚的是为什么编译器不能进一步限制 的返回类型copy
,或者如何向编译器指示返回的值不是引用。
解决方案
没有任何东西copy
限制R
特定的具体类型。特别是,&f64
可以实现(不仅仅是)Borrow<R>
的多个值。它不在您当前的代码中,但缺乏替代方案不被视为选择特定实现的理由。R
f64
我什至可以添加一个匹配的实现:
#[derive(Copy, Clone, Debug, Default)]
struct Foo;
impl Borrow<Foo> for &f64 {
fn borrow(&self) -> &Foo { &Foo }
}
(即使f64
是标准库类型,也允许此 trait 实现,因为Foo
它是在当前 crate 中定义的类型。)
现在我们可以实际使用选择:
fn main() {
dbg!(copy::<f64, _>(&1.0));
dbg!(copy::<Foo, _>(&1.0));
}
[src/main.rs:19] copy::<f64, _>(&1.0) = 1.0
[src/main.rs:20] copy::<Foo, _>(&1.0) = Foo
当返回类型实际上取决于参数类型时, like 函数copy
只能从其参数类型派生其返回类型:例如,如果它是由参数实现的关联类型的 trait。两者都有一个类型参数而不是关联类型(因此可以为同一个实现类型多次实现);有一个关联类型,但不提供 from to 。您可以为此实现自己的特征:AsRef
Borrow
Deref
Target
Deref
f64
f64
trait DerefCopy: Copy {
type Output;
fn deref_copy(self) -> Self::Output;
}
impl<T: Copy> DerefCopy for &T {
type Output = T;
fn deref_copy(self) -> T {
*self
}
}
impl DerefCopy for f64 {
type Output = Self;
fn deref_copy(self) -> Self {
self
}
}
fn main() {
assert_eq!(6, (&6).deref_copy());
assert_eq!(6, (6).deref_copy());
assert_eq!(6.0, (&6.0).deref_copy());
assert!((6.0f64 - (&6.0f64).deref_copy()).abs() < 1e-6);
}
但是,这将要求您为希望使用它DerefCopy
的每个非引用类型实现,因为不可能为所有非引用 T
编写一揽子实现;Borrow
可以有一个全面实现的原因是impl Borrow<T> for T
不冲突,impl Borrow<T> for &T
因为如果我们假设 T 本身是一个引用&U
,我们得到impl Borrow<&U> for &&U
的仍然不一样impl Borrow<T> for T
。
推荐阅读
- android - 任何 android Studio 版本 > 3.2.1 显示红色资源但仍可编译
- c# - 如何将自定义属性添加到 IdentityServer4 PersistedGrantStore
- c++ - 以基类作为数据成员的派生类?
- identityserver4 - 是否可以调用 IdentityServer4 API 来发布令牌?
- bash - 要求输入 bash 脚本的命令
- android - Android Studio 编辑器在更新到 3.5 后看不到数据绑定引用
- java - Spring Boot 1.5 禁用 oauth2 安全性
- go - 使用反射设置作为指针的结构字段
- javascript - 如何使用 javascript 在浏览器中检索 keberos 票证
- c# - 在 RDLC 报告 FromDate 到 ToDate 中搜索记录