web-dev-qa-db-ja.com

なぜF#、RustなどがC#8やTypeScriptのようなNull可能型の代わりにオプション型を使用するのですか?

AFAIK、Optionタイプはランタイムオーバーヘッドがありますが、Option時間は列挙型(メモリを消費する)であるため、null許容タイプはありません。

オプションの参照をオプションとしてマークするだけでなく、コンパイラーはコードの実行を追跡して、nullになり得ないときはいつでも見つけることができますか?

編集:誤解されているようです。 nullポインターを回避することの利点を理解し、同意します。私はnullを受け入れる任意のポインタについて話しているのではありません。 C#8のnull可能な参照型や厳密なnullチェック付きのTypeScriptなど、コンパイル時のメタデータを使用しない理由を尋ねているだけです。デフォルトのポインターはnullにできず、受け入れることができるポインターを示す特別な構文(主に?)があります。ヌル。

編集2

また、Someは私の意見では奇妙です。暗黙的な変換の方が良いでしょう。しかし、それは言語機能であり、関連性はありません。

71
Chayim Friedman

ヌル可能/非ヌルポインターのセマンティクスは非常に複雑です。

関数fがnull可能なポインタを引数として受け取り、それをnull以外のポインタを持つ関数gに渡したいとしましょう。明らかに、ポインタがnullでない場合のみ。 g(p)はコンパイル時エラーを与えます。 "if(p!= nil)g(p)"はどうですか?うまくいくはずですが、違いは何ですか?pはまだですnullableポインター。つまり、ifステートメントの後はpをnullにできないことをコンパイラーが十分に理解している必要があります。そのため、コンパイラーに大幅な変更を加えるか、機能がまったく役に立たなくなります。

Swiftでオプションを取ります。それらはどのように作成されますか?

まず、Swiftには非常に一般的で非常に便利な機能があります。関連付けられた値を持つ列挙型です。つまり、列挙型のすべてのケースで、プログラマはそのケースの列挙型値に格納される値を定義できます。この機能は、オプションを実装するために使用されます。オプションは、「none」と「some」の2つのケースを持つ列挙型であり、「none」ケースには関連データがなく、「some」ケースにはあります。オプションは言語の一部でもなく、標準ライブラリに実装されています。

「nil」はどうですか? nilはリテラルであり、数値または文字列リテラルに似ています。したがって、nilはコンパイラーに実装されています。 nilは「NilConvertibleLiteral」に変換されます(私はおそらくこれを間違ってつづっています)。 Optionalsが実装されている標準ライブラリでは、オペランドが "NilConvertibleLiteral"の場合、代入演算子と等号/不等号演算子がオーバーロードされるため、optional == nilは "optional case is" none "として実装されます。 「13」または「3.1415e-20」をコンパイルする方法と同じように「nil」をコンパイルする方法を知っているコンパイラの小さなビットを除いて、標準ライブラリに実装されています。また、すべての標準ライブラリで比較が定義されていますオプションと非オプションの組み合わせ:nilオプションはnilオプションと等しく、非nilオプションと等しくなく、2つの非nilオプションはそれらの値を比較します。

構文糖には2つのビットがあります。そして!演算子。変数をTとして宣言しますか?またはT! T?.xは、Tがnilでない場合はxを返し、Tがnilの場合はnilを返します。 T!.xは、Tがnilでない場合はxを返し、Tがnilの場合は保証でクラッシュします。上記の例では、オプション以外のオプションが必要な場合にオプションを使用できないため、「g(p)」はコンパイルされません。「g(p!)」は、pがnilの場合、「if p != nil {g(p!)}はクラッシュできません。

構文糖のもう1つのビットがすべての違いを生みます: "if let x = expression {...} else {...}。expressionはオプションの値でなければなりません。nilでない場合、オプションではない値が抽出されますxに割り当てられ、最初のステートメントリストが実行されます。式がnilの場合、2番目のステートメントリストが実行されます(オプション)。これは、オプションがnilであるかどうかのチェックと非オプション値の作成を組み合わせます。

Null可能およびnull以外のポインターの利点:1.すべてに使用できます。文字列を整数に変換する関数のように、オプションのIntを返すので、「if let i = Int(string){success} else {failure}と書くと、テストを回避できません。2.非常にクリーンです。セマンティクス3. 3. guaranteedクラッシュを引き起こす可能性のある!を使用しない限り、nilテストを回避することはできません(そして!は、それを要求していることを意味します)。オプションではない値の場合。Objective-CをSwiftに変換すると、多くの偏執的なnilテストが消えるのがわかりました。

0
gnasher729