【问题标题】:How to return a reference from a trait when combining types into enum将类型组合成枚举时如何从特征返回引用
【发布时间】:2015-07-31 19:42:13
【问题描述】:

我有点卡住了(除了复制我的记忆(参见playpen 中的 DupKeyEAB),我得到了这个特征:

   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 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>;
    }

或直接(以 KeyRef 作为特征)

  fn get_key_ref<'a,K : KeyRef<'a>>(&'a self) -> K;

   fn get_key_ref<'a>(&'a self) -> KeyRef<'a>;

所有这些符号显然都非常无效,但它说明我需要返回一个与实现我的特征的结构具有相同生命周期的引用,但同时该引用不能简单地是 &'a 而是一个枚举相同的寿命。

这样,当在简单结构上使用 get_key_ref 时,我的 KeyRef 只是 &'aKey,当在 枚举组合多个特征实现上使用 get_key_ref 时(请参阅EnumAB),我可以在引用上使用包装枚举到关键:像KeyABRef&lt;'a&gt;

  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()),
       }
     }
   }

但我不能在我的特质中包含这个功能。 我想知道是否有人为这种需求找到了解决方案(KeyVal 需要是“静态的”)?

我原来的测试代码是:

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);
}

【问题讨论】:

  • 您能否提供一个您要解决的问题的最小可编译示例?您现在的问题是关于对某些尚未描述的问题的尝试的无效解决方案。您很有可能可以在安全的 Rust 中解决您最初的问题。

标签: enums rust


【解决方案1】:

我同意 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());
}

【讨论】:

  • 第二个代码似乎解决了这个问题:这正是我 needed 的内容。我原本不想使用 KeyVal 因为它会影响整个程序的生命周期,但似乎我别无选择。感谢您的回复。
  • 我过早地感到高兴,在完成使用 spawn 的测试后,我又遇到了问题(请参阅playpen),作为 trait 参数的生命周期似乎与 spawn 使用冲突(没有它不会)。
  • 使用 HRTB 进行产卵,似乎我可以运行我的 spawn 函数(我更新了原始帖子中的代码),这可能很好(我需要记录更多关于 HRTB 的信息才能感到舒服使用这个)。
【解决方案2】:

使用 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);

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-05
    • 2013-03-13
    • 1970-01-01
    • 2023-02-21
    • 1970-01-01
    • 1970-01-01
    • 2018-02-23
    相关资源
    最近更新 更多