次のKotlinコード:
val x = null + null
結果として、x
はString
タイプになります。これは String.plus
:
この文字列を、指定された[other]オブジェクトの文字列表現と連結します。レシーバーまたは[その他]オブジェクトのいずれかがnullの場合、それらは文字列「null」として表されます。
しかし、なぜこれが起こるのか分かりません-言語の特別な機能が原因ですか?
おそらく、String?.plus(Any?)
は、Kotlinライブラリでnull許容型をレシーバーとして受け入れる唯一のplus
関数だからです。したがって、null + null
を呼び出すと、コンパイラは最初のnull
をString?
として扱います。
レシーバータイプがInt?
で、戻り値のタイプがInt
である拡張関数を定義する場合、x
はInt
として推論されます。
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
val x = null + null
以下のように言い換えると、答えがわかります。
val x = null.plus(null)
以下は、IntelliJがplus
メソッドのシグネチャとして示しているものです。
public operator fun String?.plus(other: Any?): String
したがって、最初のnull
はString?
タイプとして扱われ、その後、他のものを追加しようとすると、上記のplus
メソッドが唯一の一致になります。 x
を印刷するとnullnull
になります
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
を許可する