web-dev-qa-db-ja.com

Kotlinでnull + nullの型が暗黙的にStringになるのはなぜですか?

次のKotlinコード:

val x = null + null

結果として、xStringタイプになります。これは String.plus

この文字列を、指定された[other]オブジェクトの文字列表現と連結します。レシーバーまたは[その他]オブジェクトのいずれかがnullの場合、それらは文字列「null」として表されます。

しかし、なぜこれが起こるのか分かりません-言語の特別な機能が原因ですか?

32
Morozov

おそらく、String?.plus(Any?)は、Kotlinライブラリでnull許容型をレシーバーとして受け入れる唯一のplus関数だからです。したがって、null + nullを呼び出すと、コンパイラは最初のnullString?として扱います。

レシーバータイプがInt?で、戻り値のタイプがIntである拡張関数を定義する場合、xIntとして推論されます。

public operator fun Int?.plus(other: Any?): Int = 1
val x = null + null

同じファイル内で別の同様の関数(レシーバー型としてnull許容型)を宣言すると、null + nullを呼び出すと、コンパイル時エラーが発生します:Overload resolution ambiguity. All these functions match.

public operator fun Int?.plus(other: Any?): Int = 1
public operator fun Float?.plus(other: Any?): Float = 1F
val x = null + null    //compile time error
44
BakaWaii
val x = null + null

以下のように言い換えると、答えがわかります。

val x = null.plus(null)

以下は、IntelliJがplusメソッドのシグネチャとして示しているものです。

public operator fun String?.plus(other: Any?): String

したがって、最初のnullString?タイプとして扱われ、その後、他のものを追加しようとすると、上記のplusメソッドが唯一の一致になります。 xを印刷するとnullnullになります

4
Henry

Nothingのタイプから始める必要があります。このタイプは、可能な値がまったくゼロです。これは ボトムタイプ であり、他のすべてのタイプのサブタイプです(Anyと混同しないでください。これは 他のすべてのタイプのスーパータイプ です)。 Nothingは任意の型に強制変換できるため、次のようなことができます。

fun doStuff(a: Int): String =
    TODO("this typechecks")

タイプNothing?、つまりNothingまたはnullに移ります。 0 + 1の可能な値があります。したがって、nullのタイプはNothing?です。 Nothing?は、null許容型に強制変換できるため、次のようなことができます。

var name: String? = null

ここでnull : Nothing?String?に強制変換されます。

何らかの理由で、残念ながら この関数はstdlibで定義されています

operator fun String?.plus(other: Any?): String

上記の強制ルールを利用してnull + nullを許可する

4