2017-03-08 1 views
5

어떻게 차별 된 조합원의 이름이 지정된 필드에 액세스 할 수 있습니까?DU 회원의 이름이 지정된 필드에 액세스

예 :도 일치하는 방법을 언급

let x, y = 
    match p with 
    | Point (x1, y1) -> x1, y1 

The F# documentation : 당신은 match를 통해 필드에 액세스 할 : 다른 모든 조합 유형처럼 작동라는 이름의 필드

일반적으로
type Point = | Point of x : int * y : int 
let p = Point(3, 1) 
// how to access x-value or y-value of p here? 

답변

4

, 노동 조합 일부 명명 된 매개 변수 만. 귀하의 경우, 이것은 당신이 쓸 수있는 의미

당신은 모두가 하나 인 경우에
let xOnly = 
    match p with 
    | Point (x = x1) -> x1 

는, @의 p.s.w.g으로 대답을 참조하십시오. 그 대답의 코드는 모든 차별 노동 조합에 대해 일반적입니다. 라는 이름의 필드가 단일 노조를 들어, 위의 특수 구문을 사용하여 작성할 수 있습니다

let Point(x = myX) = p 

이것은 myX에 필드 x의 값을 결합한다.

PS 의견에 따라 : p.x을 통해 왜 즉시 필드를 읽을 수 없습니까? 차별화 된 유니온을 작은 개체 계층 구조로 생각할 수 있습니다. (같은 것을 사용하면 discriminated union documentation : "작은 개체 계층 구조의 더 단순한 대안으로 차별화 된 유니온을 사용할 수 있습니다"참조). 다음 DU를 고려하십시오.

type Shape = | Circle of r: float | Square of float 

수퍼 클래스로 Shape을 볼 수 있습니다. CircleSquare은 두 개의 파생 클래스이며 각 클래스는 단일 float 속성을가집니다. 생성하는 Circle 또는 Square의 각 인스턴스는 업 캐스트되어 Shape이됩니다.

그 이유는 필드를 즉시 읽을 수없는 이유입니다. 먼저 원하는 파생 클래스를 설정해야합니다. 올바른 하위 클래스로 캐스트 한 후에야 필드를 읽을 수 있습니다 .

이 객체의 계층 구조보기는 하위 사용자가 F 번호로 내부적으로 처리하는 방법에 매우 밀접하게 일치 :

> typeof<Shape>.GetNestedTypes() 
|> Seq.iter (fun t -> 
    let p = t.GetProperties() 
    let s = 
     p 
     |> Array.map (fun p -> sprintf "%s: %s" p.Name p.PropertyType.Name) 
     |> String.concat "; " 
    printfn "Nested type %s: %i Properties %s" t.Name p.Length s 
);; 
Nested type Tags: 0 Properties 
Nested type Circle: 4 Properties r: Double; Tag: Int32; IsCircle: Boolean; IsSquare: Boolean 
Nested type Square: 4 Properties Item: Double; Tag: Int32; IsCircle: Boolean; IsSquare: Boolean 
: 당신이 반사의 DU 유형을 보면, 당신은 당신의 노동 조합의 경우 같은 이름을 가진 두 개의 중첩 된 유형이 표시됩니다

실제 데이터는 하위 클래스의 속성에 있습니다. Circle의 경우 명명 된 필드를 사용하면 r 속성이 표시됩니다. Square의 경우 Item 속성에 데이터가 있고 (복수 인수가있는 경우 Item1, Item2) 데이터가 있습니다. 나머지는 컴파일러에 의해 생성 된 것입니다 : 숫자 Tag은 서브 클래스를 빠르게 구별하는데 사용되며, 서브 클래스 검사를위한 2 개의 bool 속성입니다.

당신의 예와 같이 하나의 경우 차별 노동 조합에 대한
>  typeof<Shape>.GetProperties() 
    |> Seq.iter (fun p -> printfn "Property %s" p.Name);; 
Property Tag 
Property IsCircle 
Property IsSquare 
+0

이 같은 것을 달성하기위한 어떤 짧은 구문이없는'P2 = 점 (PX, PY)을 보자' ? –

+1

일반적으로 여러 개의 결합 케이스가있는 경우 : 아니오. 'p'는'Point' case를 표현하는 객체가 될 수 있습니다. OOP 용어로 생각하면 :'p'는 수퍼 클래스의 인스턴스이지만 파생 클래스의 필드에 액세스하려고합니다. 'match'는 캐스트에 해당하는 것을 수행하고 필드를 액세스 가능하게 만듭니다. –

+1

@no_mindset, 단 하나의 case 만 있고 더 짧은 구문에 관심이 있다면, union이 아닌 record를 사용하십시오. –

5

, 당신이 match-with 표현을 사용할 필요가 없습니다 :

슈퍼 클래스 자체는 컴파일러가 생성 속성이 있습니다.당신은 단지이 작업을 수행 할 수 있습니다 :

let (Point (x, y)) = p 
printf "%i" x // 3 

하거나 x을 얻고 y 무시 :

let (Point (x, _)) = p 
printf "%i" x // 3