Kotlin Unit の特徴をまとめてみた
Unit
は、Kotlinで最も頻繁に使用される型の一つでありながら、その存在感は意外と薄いものです。
JavaからKotlinに移行した多くのプログラマーにとって、KotlinがJavaのvoid
型ではなく、新たにUnit
という概念を導入した理由は疑問に思えるかもしれません。
実際には、Unit
を完全に理解していなくても、Kotlinの開発を問題なく進めることは可能です。
しかし、Unit
はKotlinの文法設計と密接に関係しており、Kotlin開発において静かに重要な役割を果たしています。
Unit とは
Unit
を理解する最も直接的な方法は、ソースコードを読むことです。
package kotlin
/**
* The type with only one value: the `Unit` object. This type corresponds
* to the `void` type in Java.
*/
public object Unit {
override fun toString() = "kotlin.Unit"
}
これはUnit
のソースコードです。
ソースコードから分かるように、Unit
はKotlinのクラスであり、またはSingleton Objectです。
Unit の用途
Unit
は公式に定義された概念であり、何の値も返す必要がない場合の戻り値として使用されて、関数が意味のある値を返さないことを示します。
Javaのvoid
に似ています。
Unit と void
Kotlinには本当に値を返さない関数が存在しません。
見た目上戻り値なしの関数の戻り値の型、実際にはUnit
です。
見た目上戻り値なしように見えるのは、Kotlinが省略された部分を自動的に補完してくれるためです。
例えば、以下の2つのコードは完全に同じであり、戻り値の型としてのUnit
と戻り値のUnit
オブジェクトは省略できます:
fun main() {
println("Hello world!")
}
fun main(): Unit {
println("Hello world!")
return Unit
}
これがKotlinのUnit
とJavaのvoid
の本質的な違いです。
なぜこのように設計されているのですか?
このように設計されたメリットは、void
を特別に扱う必要がないことです。
例えば、Javaコードは次のようになります。
abstract class Base<T> {
public abstract T make();
}
class Impl extends Base<Result> {
@Override
public Result make() {
return new Result();
}
}
以下のような、Base
を継承したNil
クラスの場合、make
メソッドでは「何の値も返す必要がない」ですが、継承とGenericsの制限のために、void
とは異なるVoid
を導入する必要があり、Void
クラスとreturn null
を使用して実装されます。
class Nil extends Base<Void> {
@Override
public Void make() {
return null;
}
}
一方、Kotlinでは、通常の関数と同じ方法で処理され、追加の概念を導入する必要がなくなります。
internal class Nil : Base<Unit>() {
override fun make() {}
}
同様に、この方法は関数式にも適用できます。
fun run(block: () -> Any) { TODO() }
run { "String" } // () -> String
run { 0 } // () -> Int
run {} // () -> Unit
Everything is an Expression
PythonやScalaなどの言語と同じ、Kotlin言語は「Everything is an Expression(一切皆有返回值)」というデザイン理念に基づいています。
これは、Kotlinがvoid
型の特殊性を排除する根本的な理由でもあります。
「Everything is an Expression」という設計理念は、void
以外にも適用されているところがあります、例えば:
- 戻り値はある
if-else
文
fun run(flag: Boolean) {
val value = if (flag) "Kotlin" else "Java"
println("Hello $value!")
}
fun run(flag: Int) {
val value = if (flag == 0) {
"Kotlin"
} else if (flag > 0) {
"Java"
} else {
"?"
}
println("Hello $value!")
}
- 戻り値がある
when expression
fun run(flag: Boolean) {
val value = when(flag) {
true -> "Kotlin"
else -> "Java"
}
println("Hello $value!")
}
fun run(flag: Int) {
val value = when {
flag == 0 -> "Kotlin"
flag > 0 -> "Java"
else -> "?"
}
println("Hello $value!")
}
まとめ
Kotlinでは、Unit
型が重要な役割を果たしており、関数が意味のある値を返さないことを示しています。Unit
型を一貫して使用することで、Kotlinはvoid
の特別性を排除し、関数シグネチャをより統一し、コードをより簡潔に明確にします。