错误消息说“graphics::character::CharacterCache
未实现&mut C
”;实际上,您在 -where
子句中所说的只是C: CharacterCache
,而不是 &mut C: CharacterCache
。
(一般来说,&mut Type: Trait
如果所有人都知道,则无法得出结论Type: Trait
)
我假设.draw
您正在调用的方法需要self.properties: Text
a&mut C
作为其参数,因此您可能可以传入font
or &mut *font
,但我猜测您的额外间接级别 via&mut font
会导致那里出现问题。
换句话说:
self.properties.draw(
self.text.as_str(),
&mut font,
// ~~~~~~~~~ is not the same as `font` or `&mut *font`
&draw_state,
transform,
g,
);
给有经验的 Rustaceans 的旁注:
这种编码“错误”(增加了一层间接性)实际上比您在使用 Rust 编程时可能想象的要多。
然而,人们通常不会注意到这一点,因为编译器通常会将预期类型与提供的类型进行比较,并且会应用所谓的deref 强制将给定值转换为适当的参数。
因此,如果您考虑以下代码:
fn gimme_ref_to_i32(x: &i32, amt: i32) -> i32 { *x + amt }
fn gimme_mutref_to_i32(x: &mut i32, amt: i32) { *x += amt; }
let mut concrete = 0;
gimme_mutref_to_i32(&mut concrete, 1);
gimme_mutref_to_i32(&mut &mut concrete, 20);
let i1 = gimme_ref_to_i32(&concrete, 300);
let i2 = gimme_ref_to_i32(& &concrete, 4000);
println!("concrete: {} i1: {} i2: {}", concrete, i1, i2);
它将毫无问题地运行;编译器将自动在借用下方插入取消引用,变成&mut &mut concrete
into&mut *(&mut concrete)
和& &concrete
into & *(&concrete)
(在这种情况下分别称为和)&mut concrete
。&concrete
(您可以通过阅读相关的RFC了解更多关于 Deref Coercions 的历史。)
然而,当我们调用的函数需要一个类型参数的引用时,这个魔法并不能拯救我们,就像这样:
fn gimme_mutref_to_abs<T: AddAssign>(x: &mut T, amt: T) { *x += amt; }
let mut abstract_ = 0;
gimme_mutref_to_abs(&mut abstract_, 1);
gimme_mutref_to_abs(&mut &mut abstract_, 1);
// ^^^^ ^^^^^^^^^^^^^^
// compiler wants &mut T where T: AddAssign
println!("abstract: {}", abstract_);
在这段代码中,Rust 编译器开始假设输入类型 ( &mut &mut i32
) 将分解为&mut T
满足T: AddAssign
.
它检查第一个可能匹配的案例:剥离第一个&mut
,然后查看剩余的 ( &mut i32
) 是否可能是T
我们正在搜索的那个。
&mut i32
没有实现AddAssign
,因此解决特征约束的尝试失败。
这是关键:编译器不会决定尝试在此处应用任何强制(包括 deref 强制);它只是放弃了。我没有设法找到放弃这里的依据的历史记录,但我从对话中(以及从编译器的知识)中的记忆是特征解析步骤很昂贵,所以我们选择不尝试搜索潜在的特征在每一步的强制。相反,程序员应该找出一个适当的转换表达式,将给定的类型转换为编译器可以T
接受的某种中间类型作为预期类型。U