[英]How to specify generics that can be dereferenced into a trait
I have structs A
and B
, where B
can be dereferenced into A
.我有结构
A
和B
,其中B
可以取消引用到A
。
A
implements GetValue
with the function .get_value()
, and therefore B
also indirectly implements GetValue
. A
使用函数.get_value()
实现GetValue
,因此B
也间接实现GetValue
。
Now I'd like to write a function print_value
that can accept &A
and &B
, so it can internally call .get_value()
on them.现在我想写一个函数
print_value
可以接受&A
和&B
,所以它可以在内部调用.get_value()
。 Technically this should be possible, because both of them can be dereferenced into &GetValue
;从技术上讲,这应该是可能的,因为它们都可以取消引用到
&GetValue
; &A
by dereferencing once, and &B
by dereferencing twice. &A
通过取消引用一次, &B
通过取消引用两次。
The question is: How do I specify the generic of print_value
to achieve this?问题是:如何指定
print_value
的泛型来实现这一点?
Here is my attempt:这是我的尝试:
use std::ops::Deref;
//### external library code ######################
struct A(i32);
struct B(A);
impl Deref for B {
type Target = A;
fn deref(&self) -> &Self::Target {
&self.0
}
}
trait GetValue {
fn get_value(&self) -> i32;
}
impl GetValue for A {
fn get_value(&self) -> i32 {
self.0
}
}
//### my code ####################################
fn print_value<T: Deref>(val: T)
where
<T as Deref>::Target: GetValue,
{
println!("{}", val.get_value())
}
fn main() {
let a = A(1);
let b = B(A(2));
println!("{}", a.get_value());
println!("{}", b.get_value());
print_value(&a);
print_value(&b); // < fails with error "the trait bound `B: GetValue` is not satisfied"
}
The problem here is that <T as Deref>::Target: GetValue
does not match &B
, because &B
would have to be dereferenced twice.这里的问题是
<T as Deref>::Target: GetValue
不匹配&B
,因为&B
必须被取消引用两次。 The compiler automatically dereferences many times when a function is called, so is there a way to achieve the same through generics?调用函数时编译器会自动多次取消引用,那么有没有办法通过泛型来实现呢?
I only have power over the implementation of print_value
.我只有执行
print_value
的权力。 I do not have the power over the other functions.我没有其他功能的权力。
A more real-life example would be:一个更真实的例子是:
get_value
= get_error_source
get_value
= get_error_source
A
= an error type A
= 错误类型B
= Box<dyn A>
B
= Box<dyn A>
GetValue
= std::error::Error
GetValue
= std::error::Error
I just wanted to keep it as abstract as possible to avoid confusion.我只是想让它尽可能抽象以避免混淆。 I'm still quite certain that this is not an XY problem.
我仍然很确定这不是 XY 问题。
Instead of making a function have an overly complicated signature just to signify that it can take anything that you know to get_value
of, you could do a blanket implementation.与其让一个函数有一个过于复杂的签名来表示它可以获取你知道的任何东西来
get_value
值,你可以做一个全面的实现。 This way, you automatically signify that something you can get_value
of, well, you can get_value
of.这样,您会自动表示您可以
get_value
of,嗯,您可以get_value
of。
impl<T> GetValue for T
where
T: Deref,
<T as Deref>::Target: GetValue,
{
fn get_value(&self) -> i32 {
self.deref().get_value()
}
}
Just adding that makes it work, see the playground .只需添加它即可使其工作, 请参阅操场。
You just need to actually call deref
on the object, then you would pass a B
or an &A
:您只需要在对象上实际调用
deref
,然后您将传递B
或&A
:
use std::ops::Deref;
...
fn print_value<T: Deref>(val: T)
where
<T as Deref>::Target: GetValue,
{
println!("{}", val.deref().get_value())
}
fn main() {
let a = A(1);
let b = B(A(2));
println!("{}", a.get_value());
println!("{}", b.get_value());
print_value(&a);
print_value(b);
}
Outputs:输出:
1
2
1
2
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.