14

CompilationRepresentationFlags.UseNullAsTrueValueに使用することができます

識別された共用体のnullarydiscriminatorsの表現としてnullの使用を許可する

Option.Noneこれの最も顕著な例です。

なぜこれが便利なのですか?nullチェックは、ユニオンケース(生成されたTagプロパティ)をチェックするための従来のメカニズムよりも優れていますか?

それはおそらく予期しない動作につながります:

Some(1).ToString() //"Some(1)"
None.ToString()    //NullReferenceException

編集

静的な読み取り専用フィールドの代わりにnullと比較する方が速いというJackの主張をテストしました。

[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>]
type T<'T> =
  | Z
  | X of 'T

let t = Z

ILSpyを使用すると、t(予想どおりに)nullにコンパイルされることがわかります。

public static Test.T<a> t<a>()
{
    return null;
}

テスト:

let mutable i = 0
for _ in 1 .. 10000000 do
  match t with
  | Z -> i <- i + 1
  | _ -> ()

結果:

実数:00:00:00.036、CPU:00:00:00.046、GC gen0:0、gen1:0、gen2:0

CompilationRepresentation属性が削除されると、静的な読み取り専用フィールドになりtます。

public static Test.T<a> t<a>()
{
    return Test.T<a>.Z;
}

public static Test.T<T> Z
{
    [CompilationMapping(SourceConstructFlags.UnionCase, 0)]
    get
    {
        return Test.T<T>._unique_Z;
    }
}

internal static readonly Test.T<T> _unique_Z = new Test.T<T>._Z();

そして結果は同じです:

実数:00:00:00.036、CPU:00:00:00.031、GC gen0:0、gen1:0、gen2:0

t == nullパターンマッチは、前者と後者の場合と同様にコンパイルされt is Zます。

4

2 に答える 2

10

F#コンパイラはnull、FSharpOption <'T>のインスタンスを実際に作成してプロパティをチェックするよりも効率的であるため、Noneの表現として使用することがありTagます。

考えてみてください。nullが許可されていない通常のF#タイプ(レコードなど)がある場合、そのタイプのインスタンスへのポインター(CLRによって内部的に使用されるポインター)は決してなりませんNULL。同時に、が状態を表すことができるタイプである場合、は状態Tを表すことができます。したがって、Noneの表現として使用すると、F#型ではnullが許可されないという事実によって利用できる、その1つの追加の状態値を利用するだけです。nT optionn+1null

この動作をオフにしてみたい場合(通常のF#タイプの場合)、それらに適用できます[<AllowNullLiteral(true)>]

于 2012-08-14T19:39:55.953 に答える
6

ジャックの答えは良いようですが、少し拡張すると、ILレベルでは、CLRはnull値をロードするための特定のオペコード(ldnull)とそれらをテストする効率的な手段(ldnull後にbeq/ bne.un/ ceq/ cgt.un)を提供します。TagJITtedの場合、これらはプロパティを逆参照してそれに応じて分岐するよりも効率的です。コールごとの節約はおそらくわずかですが、オプションタイプは頻繁に使用されるため、累積的な節約が大幅に増える可能性があります。

もちろん、トレードオフがあることに注意してください。継承されたメソッドは、objnull参照例外をスローする可能性があります。これは、F#値を処理するときに//の代わりに//string xを使用する1つの理由です。残念ながら、で表される値に相当する(可能性のある)ものはありません。hash xx=yx.ToString()x.GetHashCode()x.Equals(y)x.GetType()null

于 2012-08-14T20:50:19.473 に答える