2017-03-08 3 views

答えて

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 

これはmyXにフィールドxの値をバインドします。

PSコメントごとに:p.xを実行すると、すぐにフィールドを読み取れないのはなぜですか?差別化されたユニオンを小さなオブジェクト階層と考えることができます(そして、そのようなものを使用してください。discriminated union documentation:「小さなオブジェクト階層のより簡単な代替手段として識別されたユニオンを使用することができます」を参照)。

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

Shapeをスーパークラスとして表示できます。 CircleおよびSquareは2つの派生クラスであり、それぞれが単一の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の種類を見れば、あなたは労働組合の例と同じ名前を持つ2つのネストされたタイプが表示されます

実際のデータは、サブクラスのプロパティに存在します。 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)のようなものを達成するための任意の短い構文はありません。

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

それともxを取得し、yを無視する:あなたはこれを行うことができます? –

+1

一般的なケースでは、複数のユニオンケースがあります。 'p'は' Point'の場合を表すオブジェクトですが、他のいくつかのユニオンの場合もあります。あなたがOOPの言葉でそれを考えたければ: 'p'はスーパークラスのインスタンスですが、あなたは派生クラスのフィールドにアクセスしようとしています。 'match'はキャストと等価で、フィールドにアクセス可能にします。 –

+1

@no_mindset、単一のケースしか持たず、より短い構文に興味があるなら、ユニオンではなくレコードを使用します。 –

5

を、あなたはmatch-with表現を使用する必要はありません。`

let (Point (x, _)) = p 
printf "%i" x // 3 
関連する問題