2017-03-08 21 views

Odpowiedz

4

Ogólnie, związki z wymienionych dziedzin działa podobnie jak każdy inny rodzaj związków: by uzyskać dostęp do pól poprzez match:

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

The F# documentation wspomina również sposobu dopasowywania tylko niektóre nazwane parametry. W twoim przypadku oznacza to, można napisać:

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

Jeśli wszystko masz to pojedynczy przypadek, patrz odpowiedź od @ p.s.w.g. Kod w tej odpowiedzi jest ogólny dla wszystkich dyskryminowanych związków. Dla pojedynczych związków z wymienionych dziedzin, można użyć specjalnej składni przedstawionej powyżej i napisać:

let Point(x = myX) = p 

To wiąże wartość pola x do myX.

PS zgodnie z komentarzem: Dlaczego nie można odczytać pól od razu, wykonując p.x? Możesz myśleć o dyskryminowanej unii jako małej hierarchii obiektów (i używać jej, zobacz discriminated union documentation: "Często można użyć dyskryminowanej unii jako prostszej alternatywy dla małej hierarchii obiektów"). Rozważmy następujący DU:

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

Można zobaczyć Shape jako nadrzędnej. Circle i Square to dwie pochodne klasy, każda z jedną właściwością float. Każde utworzone wystąpienie Circle lub Square zostanie zaktualizowane do wersji Shape.

Dzięki temu staje się jasne, dlaczego nie można od razu odczytać pól: najpierw trzeba ustalić, które z klas pochodnych, na które patrzysz, tylko po rzutowaniu na prawą podklasę możesz odczytać pola .

Obiekt ten widok hierarchia odpowiada bardzo dokładnie, w jaki sposób dalsi są obsługiwane wewnętrznie przez F #: Jeśli spojrzeć na rodzaj DU w odbiciu, widać dwie zagnieżdżone typy, które mają taką samą nazwę jak swoich sprawach związkowych:

> 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 

Rzeczywiste dane dotyczą właściwości podklasy. Dla Circle użyliśmy nazwanych pól, zobaczysz właściwość r. W przypadku Square mamy dane w własności Item (lub Item1, Item2, jeśli było wiele argumentów). Reszta to generowane kompilatory: pole numeryczne Tag, które będzie używane do szybkiego rozróżniania podklas i dwóch właściwości bool dla kontroli podklas.

Sam nadklasą ma tylko kompilatora generowane właściwości:

>  typeof<Shape>.GetProperties() 
    |> Seq.iter (fun p -> printfn "Property %s" p.Name);; 
Property Tag 
Property IsCircle 
Property IsSquare 
+0

nie jest krótsza składnia do osiągnięcia czegoś jak 'niech P2 = Point (px, py)' ? –

+1

W ogólnym przypadku, z wieloma przypadkami związków: nie. 'p' może być obiektem, który reprezentuje przypadek' Point', ale także kilka innych przypadków unii. Jeśli chcesz myśleć o tym w terminach OOP: 'p' jest instancją superklasy, ale próbujesz uzyskać dostęp do pól klasy pochodnej. 'Dopasowanie' ma odpowiednik rzutowania i udostępnia pola. –

+1

@no_mindset, jeśli masz tylko jeden przypadek i interesuje cię krótsza składnia, używaj rekordów, a nie związków. –

5

Dla pojedynczych przypadków dyskryminowanych związków jak twój przykład nie trzeba używać wyrażenia match-with.może po prostu to zrobić:

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

Albo po prostu x i ignorować y:

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