2016-07-04 17 views
5

Tôi đang cố gắng tạo một bộ sưu tập chứa nhiều loại có thể. Đây là một ví dụ về cách tôi muốn nó trông:Làm thế nào để tạo một loại hình cụ thể thuộc về một họ loại?

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" 

Tôi muốn khai báo các loại cụ thể vẫn còn phù hợp với loại chung. Có cách nào để tôi có thể viết mã của tôi như thế này không? Có cách nào thành ngữ hơn để làm điều này không?

+3

Bạn có hiểu rằng Component.Position và vị trí không giống nhau không? –

Trả lời

6

Có một vài điều bạn có trong mã của bạn ở đây:

Loại viết tắt (Link)

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

Loại chữ viết tắt chỉ xác định một tên khác cho một loại hiện có, các loại trên bên trái và bên phải và chính xác tương đương và có thể được sử dụng thay thế cho nhau.

Để đưa ra ví dụ thích hợp cho câu hỏi này, trong F # có chữ viết tắt loại cho tiêu chuẩn .NET List, được gọi là ResizeArray. Nó được định nghĩa như thế này:

type ResizeArray<'T> = System.Collections.Generic.List<'T> 

Nó giúp bạn tiết kiệm phải mở System.Collections.Generic để sử dụng nó và nó giúp để tránh nhầm lẫn với các list gõ F # nhưng nó không làm bất cứ điều gì khác hơn là thêm một tên mới cho một loại hiện có.

đoàn Disciminated (Link)

type Component = Position | Velocity | Appearance 

Ở đây bạn có một loại duy nhất được gọi là Component, bạn có thể nghĩ về nó như một loại duy nhất với ba cấu trúc: Position, VelocityAppearance. Bạn cũng có thể deconstruct các loại một lần nữa bằng cách sử dụng cùng ba trường hợp bằng cách phù hợp với mô hình.

ví dụ:

match comp with 
|Position -> .. 
|Velocity -> .. 
|Appearance -> .. 

Hy vọng rằng, bây giờ nó sẽ đến như là không có gì ngạc nhiên khi các loại chữ viết tắt Position mà bạn tuyên bố không có mối liên hệ với các trường hợp công đoàn Position mà bạn khai báo là một phần của các loại Component. Họ hoàn toàn độc lập với nhau.

Position có nghĩa là Vector2Component là loại liên minh hoàn toàn riêng biệt.

Giả sử bạn muốn loại Component có thể chứa nhiều thứ, bạn sẽ cần kết hợp một số giá trị với các trường hợp. Dưới đây là một ví dụ của việc tạo ra như một liên minh phân biệt đối xử:

type Component = 
    | Position of Vector2 
    | Velocity of Vector2 
    | Appearance of string 

Bây giờ, chúng ta hãy nhìn vào vấn đề tiếp theo.

Nếu chúng ta xóa các từ viết tắt kiểu và thử còn lại của mã với phân biệt đối xử liên minh mới của chúng tôi

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

Bây giờ chúng ta có một lỗi mới:

The type Position is not defined.

Vâng, hãy nhớ những gì tôi đã nói trước đó khoảng Component. Component là loại, Position không phải là một loại, đó là trường hợp công đoàn của Component.

Nếu bạn muốn chứa toàn bộ từ điển của cùng một trong các tùy chọn này, bạn có thể được tốt hơn thay đổi định nghĩa của bạn để một cái gì đó như thế này:

type ComponentDictionary = 
    |PositionDictionary of Dictionary<string, Vector2> 
    |VelocityDictionary of Dictionary<string, Vector2> 
    |AppearanceDictionary of Dictionary<string, string> 

Sau đó, bạn có thể tạo ra một ResizeArray/List trong số này.

let components = ResizeArray<ComponentDictionary>() 

Bây giờ, để dân bộ sưu tập này, chúng ta sau đó chỉ cần sử dụng các nhà xây dựng trường hợp thích hợp cho ComponentDictionary

let pos = PositionDictionary (Dictionary<string, Vector2>()) 

Bây giờ, pos là loại ComponentDictionary vì vậy chúng tôi có thể thêm nó vào các thành phần:

components.Add(pos) // No error here! 
1

Câu trả lời của TheInnerLight rất hoàn chỉnh. Tôi muốn thêm rằng có thể có một số lợi thế của việc sử dụng các loại F # thuần túy (danh sách, bản đồ hoặc dict) thay vì danh sách .Net chung chung và từ điển. Tất nhiên bạn thực sự có thể cần các bộ sưu tập chung của .NET. Dưới đây là một ví dụ đơn giản trong đó sử dụng bản đồ (hoặc dict) và tạo ra một danh sách các bản đồ thành phần khác nhau:

type Vector2 = float * float 

type Component = 
    | Position of Vector2 
    | Velocity of Vector2 
    | Appearance of string 

type Components = list<Map<string,Component>> // this is not strictly necessary 

let pos = Position(10.,20.) 
let app = Appearance "here" 

let compMap1= Map.empty<string,Component> // define an empty map for Component 
let compMap1 = compMap1.Add("key1",pos).Add("key2",app) // or: let compMap1' = dict(["key1",pos;"key2",app]) 
let compMap2 = ["key3",pos;"key4",pos] |> Map.ofList // you can create map from a list 
let (components:Components) = [compMap1;compMap2] // make a list of your maps 
let components' = [compMap1;compMap2] // or just use a generic F# list 
(* 
val components' : Map<string,Component> list = 
    [map [("key1", Position (10.0, 20.0)); ("key2", Appearance "here")]; 
    map [("key3", Position (10.0, 20.0)); ("key4", Position (10.0, 20.0))]] 
*) 

Và nếu sẽ chỉ cần một danh sách (hoặc mảng, hoặc bất cứ điều gì) chứa các loại thành phần khác nhau mà bạn có thể đã làm điều đó:

let compList = [pos;app] 
//val compList : Component list = [Position (10.0, 20.0); Appearance "here"] 
Các vấn đề liên quan