2016-07-04 2 views
5

여러 가능한 유형을 포함하는 컬렉션을 만들려고합니다. 이것은 내가 어떻게 보이길 원하는지 보여주는 예입니다 :특정 유형을 만드는 방법은 유형의 패밀리에 속합니다.

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" 

일반 유형으로 여전히 적합한 특정 유형을 선언하고 싶습니다. 이런 식으로 내 코드를 작성할 수있는 방법이 있습니까? 이것을하기위한 더 관용적 인 방법이 있습니까?

유형 약어 (Link)

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

유형 약어 그냥 기존 유형의 다른 이름을 정의의 유형 :

+3

당신은 Component.Position과 위치가 하나도 같지 않다는 것을 알고 있습니까? –

답변

6

당신이 여기에 코드에있는 몇 가지가 있습니다 있습니다 왼쪽과 오른쪽 및 정확하게 동일하며 서로 교환하여 사용할 수 있습니다.

이 질문과 관련된 예제를 제공하기 위해 F #에는 표준 .NET List에 대한 유형 약어가 있으며 ResizeArray이라고합니다. 그것은 다음과 같이 정의되어 :

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

그것은 당신이 그것을 사용하기 위해 System.Collections.Generic를 열 필요하고 F 번호에 list 유형 혼란을 방지하는 데 도움이 있지만 새 이름을 추가 이외의 아무것도하지 않는 저장 기존 유형. Position, VelocityAppearance :

Disciminated 노동 조합 (Link)

type Component = Position | Velocity | Appearance 

여기에 당신은 당신이 세 가지 생성자와 함께 하나의 유형으로 생각할 수, Component라는 하나의 유형이있다. 패턴 일치로 같은 세 가지 경우를 사용하여 다시 유형을 분해 할 수도 있습니다.

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

바라 건데, 지금 당신이 선언 된 형태의 약어 Position 당신이 Component 유형의 일부로 선언 노조의 경우 Position와 아무 관련이 없습니다 놀람으로 와야한다. 그들은 서로 완전히 독립적입니다.

PositionVector2Component은 완전히 분리 된 조합 유형입니다.

여러 항목을 포함 할 수있는 Component 유형을 원한다고 가정하면 일부 값을 사례와 연관시켜야합니다. 이제


type Component = 
    | Position of Vector2 
    | Velocity of Vector2 
    | Appearance of string 
이의 다음 문제를 살펴 보자 : 여기에 같은 차별 연합 (EU)을 만드는 예입니다.

우리는 유형 약어를 삭제하고 우리는 이제 새로운 오류가 새로운 차별 연합 (EU)

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

과 나머지 코드를 시도 할 경우 :

The type Position is not defined.

글쎄, 내가 말했듯이 기억을 약 Component입니다. Component이 유형입니다. Position은 유형이 아니며, Component의 공용 사례입니다.

이러한 옵션 중 동일한 하나의 전체 사전을 포함하고 싶었

, 당신은 이런 식으로 정의를 변경 좋을 것 :
type ComponentDictionary = 
    |PositionDictionary of Dictionary<string, Vector2> 
    |VelocityDictionary of Dictionary<string, Vector2> 
    |AppearanceDictionary of Dictionary<string, string> 

는 그런 다음 이들의 ResizeArray/ List를 만들 수 있습니다.

let components = ResizeArray<ComponentDictionary>() 

이제 채워 컬렉션을 위해, 우리는 그럼 그냥 지금 ComponentDictionary

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

에 해당하는 경우 생성자를 사용할 필요 POS 그래서 우리는 구성 요소에 추가 할 수 있습니다 유형 ComponentDictionary이다 :

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

인너 라이트의 답변은 매우 완벽합니다. 순수한 F # 형식 (목록, 맵 또는 dict)을 사용하는 것이 유리할 수도 있다는 점을 덧붙이고 싶습니다 .Net List 및 Dictionary 대신. 물론 실제로 .NET generic 콜렉션이 필요할 수도 있습니다. 다음지도 (또는 DICT)를 사용하는 간단한 예는 다양한 구성 요소지도의 목록 작성

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))]] 
*) 

을 그리고 다양한 구성 요소 유형을 보유하고 그 목록이 필요 (또는 배열, 또는 무엇이든) 만한다면 당신은 이미 수 그것을 할 :

let compList = [pos;app] 
//val compList : Component list = [Position (10.0, 20.0); Appearance "here"] 
관련 문제