rust - 如何在不知道其类型的情况下获取异构列表的各个元素?
问题描述
给定一个异构列表的实现rust
(例如 from frunk
),如何在不知道元素具体类型的情况下获得对列表中元素的引用?列表的长度是静态已知的,但不能硬编码为数字文字。
我试图通过按顺序从列表中弹出每个元素(如代码示例所示)并编写一个接受usize
索引作为参数的索引方法来获取单个元素。甚至都没有尝试编译。发布的示例是我想做的。
pub trait HList: Sized {
const LEN: usize;
type Head;
type Tail: HList;
fn push<E>(self, element: E) -> Element<E, Self> {
Element { head: element, tail: self }
}
fn pop(self) -> Option<(Self::Head, Self::Tail)>;
fn len(&self) -> usize {
Self::LEN
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
pub struct Element<H, T> {
pub head: H,
pub tail: T,
}
impl<H, T: HList> HList for Element<H, T> {
const LEN: usize = 1 + <T as HList>::LEN;
type Head = H;
type Tail = T;
fn pop(self) -> Option<(H, T)> {
Some((self.head, self.tail))
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct End;
impl HList for End {
const LEN: usize = 0;
type Head = End;
type Tail = End;
fn pop(self) -> Option<(Self::Head, Self::Tail)> {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pop_two_for() {
let h = End
.push(0usize)
.push(String::from("Hello, World"));
fn eval<H: HList>(l: H) {
for _ in 0usize..H::LEN {
let (e, l) = l.pop().unwrap();
// Do work with `e`.
}
}
eval(h);
}
}
解决方案
我找到了一个合理的递归解决方案,但只有当我可以HList
根据要完成的工作的特征要求修改特征时才有效。这对我的用例来说很好,即使它不像我希望的那样通用。
use std::fmt::Debug;
pub trait MyCustomTrait<'a>: Debug {}
impl<'a> MyCustomTrait<'a> for () {}
impl<'a> MyCustomTrait<'a> for usize {}
impl<'a> MyCustomTrait<'a> for String {}
pub trait HList: Sized {
const LEN: usize;
type Head: for<'a> MyCustomTrait<'a>;
type Tail: HList;
fn push<E>(self, element: E) -> Element<E, Self>
where
E: for<'a> MyCustomTrait<'a>,
{
Element::new(element, self)
}
fn head(&self) -> &Self::Head;
fn tail(&self) -> &Self::Tail;
fn len(&self) -> usize {
Self::LEN
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
pub struct Element<H, T>(H, T);
impl<H, T: HList> Element<H, T> {
pub fn new(head: H, tail: T) -> Self {
Element(head, tail)
}
}
impl<H, T> HList for Element<H, T>
where
H: for<'a> MyCustomTrait<'a>,
T: HList,
{
const LEN: usize = 1 + <T as HList>::LEN;
type Head = H;
type Tail = T;
fn head(&self) -> &Self::Head {
&self.0
}
fn tail(&self) -> &Self::Tail {
&self.1
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct End;
impl HList for End {
const LEN: usize = 0;
type Head = ();
type Tail = End;
fn head(&self) -> &Self::Head {
&()
}
fn tail(&self) -> &Self::Tail {
&End
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn artbitrary_recursive() {
let h = End
.push(0usize)
.push(String::from("Hello, World"));
fn eval<H: HList>(list: &H) {
if H::LEN > 0 {
let head = list.head();
// Do work here, like print the debug representation of `head`.
eprintln!("{:?}", head);
eval(list.tail());
}
}
eval(&h);
assert!(false);
}
}
推荐阅读
- asp.net-core - 如何使用 ILogger 检查当前日志级别?
- javascript - 查找嵌套对象中所有匹配键值的路径
- python - 如何加载大量数据来训练机器学习模型?
- python - TypeError: field col1: LongType can't accept object '' in type
- java - 最小值和最大值
- django-models - “没有名为 'razorpay' 的模块”:Django restframework
- postgresql - Postgres n_tup_ins 与从未分析过的表的行数不匹配
- python - 如何在一个函数调用中按块加密和解密?
- kotlin - 使用 Jetpack Compose 导航
- flutter - 使用前一个小部件的索引值