function – 如何在没有更高级别(HKT)支持的情况下在Rust中创建结构通用?

我试图使Iteratee结构通用,所以我可以传递一个不同的解析函数,并得到一个不同的Iteratee.这是非通用版本:

use std::io::{BufRead, BufReader};
use std::str::{from_utf8, Utf8Error};

#[derive(PartialEq, Debug)]
struct Cat<'a> {
    name: &'a str,
}

fn parse<'a>(slice: &'a [u8]) -> Result<Cat<'a>, Utf8Error> {
    from_utf8(slice).map(|name| Cat { name: name })
}

struct Iteratee<R>
    where R: BufRead + Sized
{
    read: R,
}

impl<R> Iteratee<R>
    where R: BufRead + Sized
{
    fn next<'a, F>(&'a mut self, fun: F)
        where F: Fn(Option<Result<Cat<'a>, Utf8Error>>) -> () + Sized
    {
        let slice = self.read.fill_buf().unwrap();
        fun(Some(parse(slice)))
        //       ^^^^^^^^^^^ How do I pull 'parse' up as a function of Iteratee
    }
}

fn main() {
    let data = &b"felix"[..];
    let read = BufReader::new(data);
    let mut iterator = Iteratee { read: read };
    iterator.next(|cat| assert_eq!(cat.unwrap().unwrap(), Cat { name: "felix" }));
}

这是我尝试使它成为通用的,但我无法使用对函数的引用或传递闭包来构造IterateeFun.

struct IterateeFun<R, P, T>
    where R: BufRead + Sized,
          P: Fn(&[u8]) -> (Result<T, Utf8Error>) + Sized
{
    read: R,
    parser: P,
}

impl<R, P, T> IterateeFun<R, P, T>
    where R: BufRead + Sized,
          P: Fn(&[u8]) -> (Result<T, Utf8Error>) + Sized
{
    fn next<'a, F>(&'a mut self, fun: F)
        where F: Fn(Option<Result<T, Utf8Error>>) -> () + Sized
    {
        let slice = self.read.fill_buf().unwrap();
        fun(Some((self.parser)(slice)))
    }
}


fn main() {
    let data = &b"felix"[..];
    let read = BufReader::new(data);
    let mut iterator = IterateeFun {
        read: read,
        parser: parse, // What can I put here?
        // I've tried a closure but then I get error[E0495]/ lifetime issues
    };

    iterator.next(|cat| assert_eq!(cat.unwrap().unwrap(), Cat { name: "felix" }));
}

我想知道如何将函数传递给如图所示的结构.或者我应该这样做作为一个特征?

最佳答案 和大多数问题一样,我只需要另一层次的间接!较高的kinded类型(HKT)显然会有所帮助,但实际上我只需要能够将一个生命周期参数与我的解析函数相关联.

受用户4815162342和Streamer的启发,我意识到我可以创造两个特征Iteratee<‘a>和解析器<‘>每个都有一个相关的类型,然后当我创建一个结合它们的实现时,我将能够组合相关的类型给我一个HKT形式:

trait Parser<'a> {
    type Output: 'a;

    fn parse(&self, &'a [u8]) -> Result<Self::Output, Utf8Error>;
}

struct CatParser;

impl<'a> Parser<'a> for CatParser{
    type Output = Cat<'a>;

    fn parse(&self, slice: &'a [u8]) -> Result<Self::Output, Utf8Error> {
        parse(slice)
    }
}

trait Iteratee<'a> {
    type Item: 'a;

    fn next<F>(&'a mut self, fun: F) where F: Fn(Option<Self::Item>) -> () + Sized;
}

struct IterateeParser<R, P> {
    read: R,
    parser: P,
}

impl<'a, R, P> Iteratee<'a> for IterateeParser<R,P> where R: BufRead + Sized, P: Parser<'a> {
    type Item = Result<P::Output, Utf8Error>;
    //                 ^^^^^^^^^ This is the magic!

    fn next<F>(&'a mut self, fun: F) where F: Fn(Option<Self::Item>) -> () + Sized {
        let slice = self.read.fill_buf().unwrap();
        fun(Some(self.parser.parse(slice)))
    }
}

fn main() {
    let data = &b"felix"[..];
    let read = BufReader::new(data);
    let mut iterator = IterateeParser { read: read, parser: CatParser };
    iterator.next(|cat| assert_eq!(cat.unwrap().unwrap(), Cat { name: "felix" }));
}

魔术线是类型Item = Result< P :: Output,Utf8Error&gt ;;

点赞