如何使特定类型属于一个类型的家庭?

Coo*_*ity 5 .net f#

我正在尝试制作一个包含多种可能类型的集合.这是我希望它看起来的一个例子:

type Position = Vector2
type Velocity = Vector2
type Appearance = String

type Component = Position | Velocity | Appearance

let components = List<Dictionary<string, Component>>()
let pos = Dictionary<string, Position>()

components.Add(pos) // Type "Position" does not match with type "Component"
Run Code Online (Sandbox Code Playgroud)

我想声明仍然适合一般类型的特定类型.有没有办法可以像这样写我的代码?有没有比较惯用的方法呢?

The*_*ght 6

您的代码中有几件事情:

类型缩写(链接)

type Position = Vector2
type Velocity = Vector2
type Appearance = String
Run Code Online (Sandbox Code Playgroud)

类型缩写只是为现有类型定义另一个名称,左侧和右侧的类型和精确等效,可以互换使用.

举一个与这个问题相关的例子,在F#中有一个标准.NET的类型缩写List,它被称为ResizeArray.它的定义如下:

type ResizeArray<'T> = System.Collections.Generic.List<'T>
Run Code Online (Sandbox Code Playgroud)

它可以节省您打开System.Collections.Generic以便使用它,它有助于避免与listF#中的类型混淆,但除了为现有类型添加新名称之外,它不会执行任何操作.

受歧视的联盟(链接)

type Component = Position | Velocity | Appearance
Run Code Online (Sandbox Code Playgroud)

在这里,你有一个单一的类型,称为Component,你可以把它作为一个单一类型三个构造函数:Position,VelocityAppearance.您还可以通过模式匹配使用相同的三种情况再次解构类型.

例如

match comp with
|Position -> ..
|Velocity -> ..
|Appearance -> ..
Run Code Online (Sandbox Code Playgroud)

希望,Position您声明的类型缩写与Position您声明为Component类型的一部分的union case没有任何关联,现在应该不足为奇 了.它们完全相互独立.

Position意味着Vector2并且Component是一种完全独立的联合类型.

假设您想要一个Component可以包含多个内容的类型,您需要将一些值与案例相关联.以下是创建此类歧视联盟的示例:

type Component = 
    | Position of Vector2
    | Velocity of Vector2
    | Appearance of string
Run Code Online (Sandbox Code Playgroud)

现在,让我们看看下一个问题.

如果我们删除类型缩写并使用我们新的Discriminated Union尝试其余代码

let components = List<Dictionary<string, Component>>()
let pos = Dictionary<string, Position>()
Run Code Online (Sandbox Code Playgroud)

我们现在有一个新错误:

类型Position未定义.

好吧,记住我之前说的话Component. Component是类型,Position不是类型,它是一个联合案例Component.

如果您想要包含这些选项中相同选项的完整词典,您可能最好将定义更改为以下内容:

type ComponentDictionary =
    |PositionDictionary of Dictionary<string, Vector2>
    |VelocityDictionary of Dictionary<string, Vector2>
    |AppearanceDictionary of Dictionary<string, string>
Run Code Online (Sandbox Code Playgroud)

然后你可以创建一个ResizeArray/ List.

let components = ResizeArray<ComponentDictionary>()
Run Code Online (Sandbox Code Playgroud)

现在,为了填充这个集合,我们只需要使用适当的case构造函数 ComponentDictionary

let pos = PositionDictionary (Dictionary<string, Vector2>())
Run Code Online (Sandbox Code Playgroud)

现在,pos是类型,ComponentDictionary所以我们可以将它添加到组件:

components.Add(pos) // No error here!
Run Code Online (Sandbox Code Playgroud)