2017-03-08 65 views
5

如何訪問受歧視的會員的指定字段?訪問DU會員的姓名字段

例子:

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

在一般情況下,工會與名爲下地幹活就像任何其他的聯盟類型:您將通過match訪問字段:

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

The F# documentation還提到匹配的一種方式只有一些命名參數。在你的情況下,這意味着你可以寫:

let xOnly = 
    match p with 
    | Point (x = x1) -> x1 

如果你只有一個案例,請參閱@ p.s.w.g的答案。該答案中的代碼對所有受歧視的工會都是通用的。對於命名字段單身工會,你可以使用上面所示的特殊語法,寫:

let Point(x = myX) = p 

這種結合現場xmyX值。

PS根據意見:爲什麼你不能通過做p.x讀出字段?您可以將受歧視的聯盟想象爲一個小對象層次結構(並使用它,請參閱discriminated union documentation:「您可以經常使用區分聯合作爲較小對象層次結構的簡單替代方法」)。考慮以下DU:

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

您可以查看Shape作爲超類。 CircleSquare是兩個派生類,每個類都有一個float屬性。您創建的CircleSquare的每個實例都將被upcast爲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 

實際數據存在於子類的屬性中。對於Circle,我們使用了命名字段,您會看到屬性r。對於Square,我們有Item屬性中的數據(如果有多個參數,則爲Item1Item2)。其餘的是編譯器生成的:數字Tag字段,將用於快速區分子類和子類檢查的兩個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'情況的對象,也可以是其他一些工會情況。如果你想用OO​​P的術語來思考它:'p'是超類的一個實例,但是你試圖訪問派生類的字段。 'match'與cast相當,並且可以訪問這些字段。 –

+1

@no_mindset,如果您只有一個案例,並且您對較短的語法感興趣,請使用記錄,而不是聯合。 –

5

對單的情況下識別聯合喜歡你的榜樣,你不需要使用match-with表達。你可能只是這樣做:

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

或者只得到x而忽略y

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