gpt4 book ai didi

generics - TOML 文档的可链接查询

转载 作者:行者123 更新时间:2023-11-29 08:16:04 27 4
gpt4 key购买 nike

我正在尝试为 TOML 文档实现可链接的查询执行。

A Query是更改 TOML 文档并可能返回另一个 Query 的东西应在其自身之后执行的对象。 Query执行的获取前一个查询的结果(如果有的话)。

问题在于返回类型是通用的。查询可能会返回 Vec<i64> , 但它的继任者可能会返回 String ...因此,一个 Query 的返回类型直接取决于其后继者的返回类型。

到目前为止,这是我的代码:

extern crate either;
extern crate toml;

use either::Either;
use toml::Value;

type Result<T> = ::std::result::Result<T, ()>; // for simplicity

pub trait Query<Prev>
where
Prev: Sized,
Self: Sized,
{
type Output: Sized;
type Next: Query<Self::Output>;

fn execute(&self, target: &mut Value, prev_result: Option<Prev>) -> Result<Self::Output>;

fn next(self) -> Option<Self::Next>;
}

fn execute_query<Q, Prev>(
doc: &mut Value,
query: &Q,
prev_result: Option<Prev>,
) -> Result<Either<Q::Output, <Q::Next as Query<Q::Output>>::Output>>
where
Q: Query<Prev>,
{
let result = query.execute(doc, prev_result)?;

if let Some(next_query) = query.next() {
let next_result: <Q::Next as Query<Q::Output>>::Output =
match execute_query(doc, &next_query, Some(result)) {
Ok(Either::Left(t)) => t,
Ok(Either::Right(t)) => return Ok(Either::Right(t)), // error happens here
Err(e) => return Err(e),
};

Ok(Either::Right(next_result))
} else {
Ok(Either::Left(result))
}
}

( playground )

错误是返回类型是递归的(因为整个问题都是递归的):

error[E0308]: mismatched types
--> src/main.rs:37:65
|
37 | Ok(Either::Right(t)) => return Ok(Either::Right(t)), // error happens here
| ^ expected type parameter, found associated type
|
= note: expected type `<<Q as Query<Prev>>::Next as Query<<Q as Query<Prev>>::Output>>::Output`
found type `<<<Q as Query<Prev>>::Next as Query<<Q as Query<Prev>>::Output>>::Next as Query<<<Q as Query<Prev>>::Next as Query<<Q as Query<Prev>>::Output>>::Output>>::Output`

标题不是很有表现力。对此我感到很抱歉,我不知道如何更好地描述。

最佳答案

解决问题的整个方法是错误的。我通过以下方式实现了它:

  • Query 特性提供了一个链接查询的功能。该函数返回一个 Chain
  • Chain 类型通过执行第一个元素并将结果(如果Ok)传递给第二个查询来实现Query

使用这个问题可以解决:

use std::marker::PhantomData;

use toml::Value;
use error::Result;

pub trait Query<Prev>
where
Prev: Sized,
Self: Sized,
{
type Output: Sized;

fn execute(&self, target: &mut Value, prev_result: Option<Prev>) -> Result<Self::Output>;

fn chain<Q>(self, other: Q) -> Chain<Self, Prev, Q>
where
Q: Query<Self::Output>,
{
Chain {
first: self,
_p: PhantomData,
second: other,
}
}
}

pub struct Chain<A, P, B>
where
A: Query<P>,
B: Query<A::Output>,
P: Sized,
{
first: A,
_p: PhantomData<P>,
second: B,
}

impl<A, P, B> Query<P> for Chain<A, P, B>
where
A: Query<P>,
B: Query<A::Output>,
P: Sized,
{
type Output = B::Output;

fn execute(&self, target: &mut Value, prev_result: Option<P>) -> Result<Self::Output> {
let p = self.first.execute(target, prev_result)?;
self.second.execute(target, Some(p))
}
}

pub trait QueryExecutor {
fn query<Q, T>(&mut self, q: &Q) -> Result<Q::Output>
where
Q: Query<T>;
}

impl QueryExecutor for Value {
fn query<Q, T>(&mut self, q: &Q) -> Result<Q::Output>
where
Q: Query<T>,
{
q.execute(self, None as Option<T>)
}
}

(包括测试的完整代码 here )

关于generics - TOML 文档的可链接查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48306882/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com