I am a bit stuck (except by duplicating my memory (see DupKeyEAB in playpen), I got this trait:
pub trait KeyVal : Send + Sync + 'static {
type Key : Clone + Debug + 'static;
fn get_key(&self) -> Self::Key;
fn get_key_ref<'a>(&'a self) -> &'a Self::Key;
}
My problem is that I need something like (to avoid using clone each time I access the key) :
pub trait KeyVal : Send + Sync + 'static {
type Key : Clone + Debug + 'static;
type KeyRef<'_> : Debug;
fn get_key(&self) -> Self::Key;
fn get_key_ref<'a>(&'a self) -> Self::KeyRef<'a>;
}
or directly (with KeyRef as a trait)
fn get_key_ref<'a,K : KeyRef<'a>>(&'a self) -> K;
or
fn get_key_ref<'a>(&'a self) -> KeyRef<'a>;
All those notations are obviously pretty invalid, but it illustrate that I need to return a reference with the same lifetime as the struct implementing my trait but at the same time the reference could not simply be &'a but also a enum with the same lifetime.
That way when using get_key_ref on simple struct my KeyRef is simply &'aKey and when using get_key_ref on enum combining multiple trait implementation (see EnumAB) I could use a wrapper enum over the reference to the key : like KeyABRef<'a>
.
impl EnumAB {
fn get_key_ok<'a>(&'a self) -> KeyABRef<'a> {
match self {
&EnumAB::A(ref a) => KeyABRef::A(a.get_key_ref()),
&EnumAB::B(ref b) => KeyABRef::B(b.get_key_ref()),
}
}
}
Yet I cannot include this function in my trait. I wonder if anyone got a solution for this kind of need (KeyVal need to be 'static)?
My original test code was :
use std::fmt::Debug;
use std::thread;
pub trait KeyVal : Send + Sync + 'static {
type Key : Clone + Debug + 'static;
fn get_key(&self) -> Self::Key;
fn get_key_ref<'a>(&'a self) -> &'a Self::Key;
}
pub fn do_something_with_spawn<KV : KeyVal> (kv : KV) {
thread::spawn ( move || {
println!("{:?}", kv.get_key_ref());
});
}
#[derive(Debug)]
pub struct StructA (usize);
#[derive(Debug)]
pub struct StructB (String);
#[derive(Debug)]
pub enum EnumAB {
A(StructA),
B(StructB),
}
impl KeyVal for StructA {
type Key = usize;
// type KeyRef<'_> = &'_ usize;
fn get_key(&self) -> Self::Key {
self.0.clone()
}
fn get_key_ref<'a>(&'a self) -> &'a Self::Key {
&self.0
}
}
impl KeyVal for StructB {
type Key = String;
// type KeyRef<'_> = &'_ String;
fn get_key(&self) -> Self::Key {
self.0.clone()
}
fn get_key_ref<'a>(&'a self) -> &'a Self::Key {
&self.0
}
}
#[derive(Clone,Debug)]
pub enum KeyAB {
A(usize),
B(String),
}
#[derive(Clone,Debug)]
pub enum KeyABRef<'a> {
A(&'a usize),
B(&'a String),
}
impl KeyVal for EnumAB {
type Key = KeyAB;
// type KeyRef<'_> = KeyABRef<'_>
fn get_key(&self) -> Self::Key {
match self {
&EnumAB::A(ref a) => KeyAB::A(a.get_key()),
&EnumAB::B(ref b) => KeyAB::B(b.get_key()),
}
}
fn get_key_ref<'a>(&'a self) -> &'a Self::Key {
panic!("cannot");
}
}
impl EnumAB {
fn get_key_ok<'a>(&'a self) -> KeyABRef<'a> {
match self {
&EnumAB::A(ref a) => KeyABRef::A(a.get_key_ref()),
&EnumAB::B(ref b) => KeyABRef::B(b.get_key_ref()),
}
}
}
#[derive(Debug)]
pub struct DupKeyEAB (KeyAB, EnumAB);
impl KeyVal for DupKeyEAB {
type Key = KeyAB;
fn get_key(&self) -> Self::Key {
self.0.clone()
}
fn get_key_ref<'a>(&'a self) -> &'a Self::Key {
&self.0
}
}
fn main () {
let d2 = StructB("hello".to_string());
let d3 = EnumAB::A(StructA(3));
println!("{:?}",d2.get_key());
println!("{:?}",d3.get_key());
println!("{:?}",d2.get_key_ref());
println!("{:?}",d3.get_key_ok());
do_something_with_spawn(d3);
}
答案 0 :(得分:2)
我同意A.B.你的动机不明确,所以我们提供的任何帮助都是最好的猜测。话虽如此,这是一个使用Borrow
的猜测:
use std::borrow::Borrow;
trait KeyVal<'a> {
type Key: Borrow<Self::KeyRef>;
type KeyRef: 'a;
fn get_key(&self) -> Self::Key;
fn get_key_ref(&'a self) -> &'a Self::KeyRef;
}
struct Example(u8);
impl<'a> KeyVal<'a> for Example {
type Key = u8;
type KeyRef = u8;
fn get_key(&self) -> Self::Key {
self.0
}
fn get_key_ref(&'a self) -> &'a Self::KeyRef {
&self.0
}
}
fn main() {
let e = Example(42);
println!("{:?}", e.get_key());
println!("{:p}", e.get_key_ref());
}
另一部分是type KeyRef: 'a
,表示所选类型必须比'a
更长。
我认为你不需要Borrow
,我想:
trait KeyVal<'a> {
type Key;
type KeyRef: 'a;
fn get_key(&self) -> Self::Key;
fn get_key_ref(&'a self) -> Self::KeyRef;
}
#[derive(Debug)]
struct Example(u8);
#[derive(Debug)]
struct RefWrapper<'a>(&'a u8);
impl<'a> KeyVal<'a> for Example {
type Key = u8;
type KeyRef = RefWrapper<'a>;
fn get_key(&self) -> Self::Key {
self.0
}
fn get_key_ref(&'a self) -> Self::KeyRef {
RefWrapper(&self.0)
}
}
fn main() {
let e = Example(42);
println!("{:?}", e.get_key());
println!("{:?}", e.get_key_ref());
}
答案 1 :(得分:1)
使用Shepmaster的解决方案(加上产生的HRTB),它变为:
use std::fmt::Debug;
use std::thread;
pub trait KeyVal<'a> : Send + Sync + 'static {
type Key : Clone + Debug + 'static;
type KeyRef : Debug + 'a;
fn get_key(&self) -> Self::Key;
fn get_key_ref(&'a self) -> Self::KeyRef;
}
pub fn do_something_with_spawn<KV> (kv : KV)
where for <'a> KV : KeyVal<'a> {
thread::spawn ( move || {
println!("{:?}", kv.get_key_ref());
});
}
#[derive(Debug)]
pub struct StructA (usize);
#[derive(Debug)]
pub struct StructB (String);
#[derive(Debug)]
pub enum EnumAB {
A(StructA),
B(StructB),
}
impl<'a> KeyVal<'a> for StructA {
type Key = usize;
type KeyRef = &'a usize;
fn get_key(&self) -> Self::Key {
self.0.clone()
}
fn get_key_ref(&'a self) -> Self::KeyRef {
&self.0
}
}
impl<'a> KeyVal<'a> for StructB {
type Key = String;
type KeyRef = &'a String;
fn get_key(&self) -> Self::Key {
self.0.clone()
}
fn get_key_ref(&'a self) -> Self::KeyRef {
&self.0
}
}
#[derive(Clone,Debug)]
pub enum KeyAB {
A(usize),
B(String),
}
#[derive(Clone,Debug)]
pub enum KeyABRef<'a> {
A(&'a usize),
B(&'a String),
}
impl<'a> KeyVal<'a> for EnumAB {
type Key = KeyAB;
type KeyRef = KeyABRef<'a>;
fn get_key(&self) -> Self::Key {
match self {
&EnumAB::A(ref a) => KeyAB::A(a.get_key()),
&EnumAB::B(ref b) => KeyAB::B(b.get_key()),
}
}
fn get_key_ref(&'a self) -> Self::KeyRef {
match self {
&EnumAB::A(ref a) => KeyABRef::A(a.get_key_ref()),
&EnumAB::B(ref b) => KeyABRef::B(b.get_key_ref()),
}
}
}
fn main () {
let d2 = StructB("hello".to_string());
let d3 = EnumAB::A(StructA(3));
println!("{:?}",d2.get_key());
println!("{:?}",d3.get_key());
println!("{:?}",d2.get_key_ref());
println!("{:?}",d3.get_key_ref());
do_something_with_spawn(d3);
}