generics - 没有类型参数的泛型类型的泛型结构

标签 generics rust higher-kinded-types

是否可以在Rust中做类似的事情?

trait Foo<T> {}

struct A;
struct B;

struct Bar<T: Foo> {
    a: T<A>,
    b: T<B>
}

我知道我可以只为Bar使用两个参数,但是我认为必须有一种更好的方法来做到这一点。

我想实现一个Graph结构。由于我不能仅将节点和边缘绑定(bind)到其父辈,因此我想使用Rc之类的东西。但是,有时可能需要带有多个线程访问权限的Graph。因此,我必须同时使用RcArc来实现。

那就是Foo的优点:我为FooRc都实现了Arc(Foo需要Deref),并且我使用了绑定(bind)到T的参数Foo。这就是我想要为单线程和多线程使用提供一个结构的方式。

最佳答案

⇒这是,目前无法在Rust的类型系统中表达

幸运的是,由于this RFC中提出的“通用关联类型”,将来有可能实现。您可以在the corresponding tracking issue中跟踪实现和稳定的状态。

这里的重要术语是“HKT”( h igher k inded t ypes)。它是Rust中尚未实现的类型系统的功能。 Haskell提供HKT。在C++世界中,HKT被称为“模板模板”。上述通用关联类型也是HKT的一种形式。

但是,香港电汇真的是什么?

让我们慢慢开始:我们知道什么是简单类型?让我们列出一些类型:i32boolString。这些都是类型...您可以拥有这些类型的值(变量)。那Vec<i32>呢?这也是一个简单的类型!您可以使用Vec<i32>类型的变量,没问题!

我们希望将这些类型组合在一起;我们称这种分类为“一种类型”。如果我们想以非常抽象的方式谈论(关于类型的类型),我们选择其他单词,在这种情况下,请选择“亲切”。甚至对各种类型都有一种表示法。对于上面的简单类型,我们说:这些类型的种类是

*

是的,只是一颗星星,非常容易。稍后,该符号更有意义!

让我们搜索与我们的简单类型不同类型的类型。 Mutex<HashMap<Vec<i32>, String>>?不,也许是相当复杂的,但是它仍然是*类型,我们仍然可以拥有该类型的变量。

Vec呢?是的,我们省略了尖括号。是的,这的确是另一种类型!我们可以使用Vec类型的变量吗?不!向量是什么?!

这种捐赠为:
* -> *

这只是说:给我一个普通类型(*),我将返回一个普通类型!给这个东西加上一个普通的i32(Vec),它将返回一个普通的Vec<i32>!它也被称为类型构造函数,因为它用于构造类型。我们甚至可以走得更远:
* -> * -> *

这有点奇怪,因为它与currying有关,并且对于非Haskell程序员来说读为奇数。但这意味着:给我两种类型,我将返回一种类型。让我们考虑一个示例... Result!提供两种具体类型ResultResult<A, B>后,A类型构造函数将返回具体类型B

术语“更高种类的类型”仅指不是*的所有类型,它们是类型构造函数。

在你的例子中

编写struct Bar<T: Foo>时,您希望T属于* -> *,即:您可以为T指定一种类型,然后接收一个简单的类型。但是正如我所说,这在Rust中尚无法表达。要使用类似的语法,可能会想到这将来可能会起作用:
// 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)借用的,现在可以将其用于生命周期中的抽象(最常与闭包一起使用)。

链接

如果您想了解更多有关此主题的信息,请参见以下链接:
  • Niko Matsakis' great series of blog posts discussing one possible solution (associated type constructors) to the HKT problem
  • The RFC proposing generic associated types (just a less scary name for "associated type constructors")
  • HRTB explanation


  • 奖励:万一实现关联的类型构造函数,您的问题的解决方案(我认为,因为没有办法进行测试)!

    我们必须绕过我们的实现,因为RFC不允许直接将Rc作为类型参数传递。可以这么说,它没有直接介绍HKT。但是正如Niko在他的博客文章中指出的那样,通过使用所谓的“家庭特征”,我们可以具有与具有关联的类型构造函数的HKT相同的灵活性和功能。
    /// 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的博客文章。困难的主题讲得足够好,甚至我都可以或多或少地理解它们!

    编辑:我刚刚注意到Niko在他的博客文章中实际上使用了Arc/Rc示例!我完全忘记了这一点,并想到了自己之上的代码……但是也许我的潜意识仍然内存犹新,因为我选择的几个名称与Niko完全一样。无论如何,这是his (probably way better) take on the issue

    关于generics - 没有类型参数的泛型类型的泛型结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64995964/

    相关文章:

    scala - 在 Scala 中创建 self 类型的实例

    java - 通用集合作为 Java 方法参数

    rust - 如何在 Rust 中的外部数据类型上实现 std::hash::Hash 特征?

    rust - 我如何实现一种方法来处理 &str、Box<str>、Rc<str> 等?

    java - 延迟绑定(bind)二级类型参数

    haskell - kind 类型 (* -> *) -> * 的仿函数和应用程序

    java - Java中未知类型的排序列表

    c# - 具有泛型类型的 nameof

    Java 1.6 : Creating an array of List<T>

    rust - TryFrom<&[T]> 和 TryFrom<Vec<T>> 有什么区别?