⇒ 这是currently impossible在Rust的类型系统中表示的☹
幸运的是,由于this RFC年提出的"通用关联类型",这在future 将成为可能.您可以在the corresponding tracking issue中跟踪实施和稳定的状态.
这里的重要术语是"HKT"(100igher 101inded 102ypes).这是尚未在Rust中实现的类型系统的一个功能.Haskell提供HKTs.在C++世界中,HTTS被称为"模板模板".上述泛型关联类型也是HKTs的一种形式.
但什么是HKT,真的吗?
让我们慢慢开始:我们所知道的简单类型是什么?让我们列出一些类型:i32
、bool
、String
.这些都是类型...可以有这些类型的值(变量).Vec<i32>
怎么样?这也是一个简单的类型!你可以有一个Vec<i32>
类型的变量,没问题!
我们想把这些类型组合在一起;我们称这种分类为"类型kind".如果我们想以一种非常抽象的方式谈论(关于类型的类型),我们可以 Select 其他单词,在本例中是kind.甚至还有kinds种类型的符号.对于上面的简单类型,我们说:这些类型是
*
是的,只是一颗星星,很简单.这个符号以后会更有意义!
让我们搜索与简单类型不同的类型.Mutex<HashMap<Vec<i32>, String>>
? 不,它可能相当复杂,但它仍然是*
类,我们仍然可以有一个这种类型的变量.
Vec
美元怎么样?是的,我们省略了尖括号.是的,这确实是另一种类型!我们能有一个Vec
型的变量吗?不what的向量?!
这类捐款的形式如下:
* -> *
这只是说:给我一个正常类型(*
),我会返回一个正常类型!给这个东西(Vec
)一个普通类型i32
,它就会返回一个普通类型Vec<i32>
!它也称为type constructor,因为它用于构造类型.我们甚至可以更进一步:
* -> * -> *
这有点奇怪,因为它与currying有关,对于非Haskell程序员来说是奇数.但这意味着:给我two种类型,我会返回一种类型.让我们考虑一个例子...Result
! 在您提供了两种混凝土类型A
和B
之后,Result
类型构造函数将返回一种混凝土类型Result<A, B>
.
术语higher kinded types只是指所有类型,它们不是*
,而是类型构造函数.
在你的例子中
当你写struct Bar<T: Foo>
的时候,你希望T
是* -> *
,意思是:你可以给T
一个类型,然后得到一个简单的类型.但正如我所说,这在铁 rust 中还没有表现出来.如果使用类似的语法,人们可能会认为这在future 可能会起作用:
// This does NOT WORK!
struct Bar<for<U> T> where T<U>: Foo {
a: T<A>,
b: T<B>,
}
for<>
语法是从"higher-ranked trait bounds" (HRTB)中borrow 而来的,现在可以使用"higher-ranked trait bounds" (HRTB)在生命周期内进行抽象(最常用于闭包).
链接
如果你想阅读更多关于这个话题的内容,这里有一些链接:
Bonus:如果相关类型构造函数将被实现,您的问题的解决方案(我认为,因为没有测试的方法)!
我们必须绕道实现,因为RFC不允许直接将Rc
作为类型参数传递.可以说,它没有直接引入HKT.但正如Niko在他的博客文章中所说,通过使用所谓的"家庭特征",我们可以拥有与HKTs相同的灵活性和力量,以及相关的类型构造器.
/// This trait will be implemented for marker types, which serve as
/// kind of a proxy to get the real type.
trait RefCountedFamily {
/// An associated type constructor. `Ptr` is a type constructor, because
/// it is generic over another type (kind * -> *).
type Ptr<T>;
}
struct RcFamily;
impl RefCountedFamily for RcFamily {
/// In this implementation we say that the type constructor to construct
/// the pointer type is `Rc`.
type Ptr<T> = Rc<T>;
}
struct ArcFamily;
impl RefCountedFamily for ArcFamily {
type Ptr<T> = Arc<T>;
}
struct Graph<P: RefCountedFamily> {
// Here we use the type constructor to build our types
nodes: P::Ptr<Node>,
edges: P::Ptr<Edge>,
}
// Using the type is a bit awkward though:
type MultiThreadedGraph = Graph<ArcFamily>;
要了解更多信息,你应该认真阅读Niko的博客帖子.困难的话题解释得足够好,甚至连我都能或多或少地理解!
EDIT:我刚刚注意到Niko在他的博客文章中使用了Arc
/Rc
的例子!我完全忘记了这一点,想到了我上面的代码...但也许我的潜意识还记得,因为我 Select 了几个名字,就像尼科一样.不管怎样,这是his (probably way better) take on the issue美元.