在没有更高种类(HKT)支持的情况下,如何在Rust中使结构通用? [英] How do I make a structure generic in Rust without higher kinded type (HKT) support?
问题描述
我正在尝试使 Iteratee
结构通用,以便我可以传递不同的解析函数并获得不同的 Iteratee
.这是有效的非通用版本:
I am trying to make the Iteratee
structure generic so I can pass in a different parsing function and get an different Iteratee
. This is the non-generic version that works:
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
.
This is my attempt at making it generic, but I can't construct IterateeFun
with either a reference to the function or passing in a closure.
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" }));
}
我想知道如何将函数传递到如图所示的结构中.还是我应该以此为特征?
I'd like to know how to pass a function into a structure as shown. Or should I be doing this as a trait instead?
推荐答案
与大多数问题一样,我只是需要另一种间接方式!更高种类的类型(HKT)显然会有所帮助,但实际上我只需要能够将生命周期参数与我的解析函数相关联.
As with most problems I just needed another level of indirection! Higher kinded types (HKT) would obviously help but I actually only need to be able to associate a lifetime parameter with my parsing function.
受到user4815162342和 Streamer 的启发我意识到我可以创建两个特征 Iteratee<'a>
和 Parser<'a>
都具有关联的类型,然后当我创建一个将它们结合在一起的实现时,我便可以将关联的类型结合起来我是HKT的一种形式:
Inspired by user4815162342 and Streamer I realised I could create two traits Iteratee<'a>
and Parser<'a>
each with an associated type and then when I create an implementation that combines them I would be able to combine the associated types to give me a form of HKTs:
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" }));
}
魔术线是 type Item = Result< P :: Output,Utf8Error> ;;
这篇关于在没有更高种类(HKT)支持的情况下,如何在Rust中使结构通用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!