blog

Kotlin入門

先ほどの例に引き続き、初期化時にKotlinコンパイラーは代入された値に基づいて型を推測することができます。...

Aug 6, 2020 · 9 min. read
シェア

Google Docsの翻訳に基づく

変数の宣言

val と var

`val` 変更された変数は、final と同様に不変である。
`var` 変更変数 変数
`var` count: `Int` = 10

変数の値を変更: count = 15.

二度と変更されたくない変数が定義されている場合は、valで変更することができます:

val languageName: String = "Kotlin"

型参照

冒頭の例を続けると、languageNameを初期化するとき、Kotlinコンパイラーは代入された値に基づいて型を推測することができます。 Kotlinは静的に型付けされた言語であり、コンパイル時に型解決が行われ、変更されないことに注意してください。これは、型解決がコンパイル時に行われ、変更されないことを意味します。以下の例では、languageNameはStringであると推論されるため、String型以外のメソッドを呼び出すことはできません。 Kotlinの型推論メソッドは、シンプルさと型の安全性を提供します。

val languageName = "Kotlin"
val upperCaseName = languageName.toUpperCase()
// Fails to compile
languageName.inc()

航空安全

言語によっては、初期値を明示せずに参照型変数を宣言することができます。 このような場合、変数には通常ヌル値が含まれます。 デフォルトでは、Kotlinの変数にNULL値を含めることはできません。 つまり、以下のスニペットは無効です:

// Fails to compile val languageName: String = null

変数がヌル値を持つには、ヌル可能な型でなければなりません。 変数の型の後に?を付けることでNULL可能な変数として指定することができます:

val languageName: String? = null

String?型では、languageNameにString値またはNULLを代入できます。

Nullになる可能性のある変数をどのように扱うか注意しなければ、恐ろしいNullPointerExceptionを発生させる可能性があります。 例えば、Javaでは、Null値でメソッドを呼び出そうとすると、プログラムがクラッシュします。

Kotlinは、null可能な変数を安全に扱うためのメカニズムを数多く提供しています。

前提条件

Kotlinには、条件ロジックを実装するためのメカニズムがいくつかあります。 その中で最も一般的なのがif-else文です。 ifキーワードの横の括弧で囲まれた式の計算結果が真であれば、その分岐内のコードが実行されます。 そうでない場合は、else分岐のコードが実行されます。

if (count == 0x2a) {
 println('I\x20have\x20the\x20answer.');
} else {
 println('The\x20answer\x20eludes\x20me.');
}

else if を使って複数の条件を表すことができます。 これにより、以下の例のように、より細かく複雑なロジックを1つの条件文で表現することができます:

if (count == 42) {
 println("I have the answer.")
} else if (count > 35) {
 println("The answer is close.")
} else {
 println("The answer eludes me.")
}

条件文は状態ロジックを表現するのに便利ですが、書いているうちに繰り返しになってしまうかもしれません。 上の例では、各ブランチで単純に文字列を表示しています。 この繰り返しを避けるために、Kotlinには条件式が用意されています。 最後の例は次のように書き換えることができます:

val answerString: String = if (count == 42) {
 "I have the answer."
} else if (count > 35) {
 "The answer is close."
} else {
 "The answer eludes me."
}
println(answerString)

暗黙のうちに、各条件分岐はその最終行の式の結果を返すので、return キーワードを使用する必要はありません。 3 つの分岐の結果はすべて String 型なので、if-else 式の結果も String 型です。 この例では、if-else 式の結果に基づいて、初期値が answerString に代入されます。 型推論を使用すると、answerString の明示的な型宣言を省略できますが、通常はわかりやすくするために型宣言を含めることをお勧めします。

注:Kotlinは伝統的な三項演算子を含まず、代わりに条件式を好みます。

条件文の複雑さが増すにつれて、次の例に示すように、if-else式をwhen式に置き換えることを検討するとよいでしょう:

val answerString = when {
 count == 42 -> "I have the answer."
 count > 35 -> "The answer is close."
 else -> "The answer eludes me."
}
println(answerString)

when式の各分岐は、条件、矢印、結果で表されます。 矢印の左側の条件が真と評価されると、右側の式の結果が返されます。 実行は分岐から次の分岐に移動しないことに注意してください。 when式の例のコードは、機能的には前の例のコードと同等ですが、間違いなく読みやすくなっています。Kotlinの追加条件文は、より強力な機能の1つであるスマートキャスティングを強調します。 NULL可能な値に対してセーフコール演算子や非NULLアサーション演算子を使用する代わりに、次の例に示すように、条件文を使用して変数にNULL値への参照が含まれているかどうかをチェックできます:

val languageName: String? = null
if (languageName != null) {
 // No need to write languageName?.toUpperCase()
 println(languageName.toUpperCase())
}

条件分岐の中では、languageNameはnullでないものとして扱うことができます。 Kotlinは、ブランチの実行がlanguageNameにNULL値が含まれていないことを条件としていることを認識するのに十分賢いので、そのブランチ内でlanguageNameをNULL可能として扱う必要はありません。 このスマートな変換は、NULLチェック、型チェック、または契約を満たすあらゆる条件に適用されます。

関数

1つまたは複数の式を1つの関数にまとめることができます。 結果が必要になるたびに同じ式を繰り返す代わりに、式を関数にまとめてその関数を呼び出すことができます。

関数を宣言するには、funキーワードの後に関数名を続けます。 次に、関数が受け取る入力の型を定義し、関数が返す出力の型を宣言します。 関数本体は、関数が呼び出されたときに呼び出される式を定義する場所です。

先ほどの例を基に、Kotlinの関数を完成させます:

fun generateAnswerString(): String {
 val answerString = if (count == 42) {
 "I have the answer."
 } else {
 "The answer eludes me"
 }
 return answerString
}

上の例の関数名は generateAnswerString です。 この関数は入力を必要としません。 String型の結果を出力します。 (関数を呼び出すには、関数の名前に続けて call 演算子を使用します)。 以下の例では、answerString 変数が generateAnswerString() の結果で初期化されます。

val answerString = generateAnswerString()

以下の例のように、関数はパラメータを入力として受け取ることができます:

fun generateAnswerString(countThreshold: Int): String {
 val answerString = if (count > countThreshold) {
 "I have the answer."
 } else {
 "The answer eludes me."
 }
 return answerString
}

関数を宣言する際は、任意の数の引数とその型を指定できます。 上記の例では、generateAnswerString() は、Int 型の countThreshold という引数を受け入れます。 関数内では、その名前を使用してパラメータを参照できます。

この関数を呼び出す際には、関数呼び出しの括弧内に引数を含める必要があります:

val answerString = generateAnswerString(42)

関数宣言の簡素化

generateAnswerString() は非常に単純な関数です。 この関数は変数を宣言し、その変数をすぐに返します。 関数から単一の式の結果を返す場合、次の例に示すように、関数に含まれる if-else 式の結果を直接返すことで、ローカル変数を宣言するステップを省略できます:

fun generateAnswerString(countThreshold: Int): String {
 return if (count > countThreshold) {
 "I have the answer."
 } else {
 "The answer eludes me."
 }
}

return キーワードを代入演算子で置き換えることもできます:

fun generateAnswerString(countThreshold: Int): String = if (count > countThreshold) {
 "I have the answer"
 } else {
 "The answer eludes me"
 }

匿名関数

すべての関数に名前が必要なわけではありません。 入力と出力で直接識別できる関数もあります。 これらの関数は無名関数と呼ばれます。 無名関数への参照を保持し、後でその参照を使用して無名関数を呼び出すことができます。 また、他の参照型と同様に、アプリケーション内で参照を渡すこともできます。

val stringLengthFunc: (String) -> Int = { input ->
 input.length
 
}

名前付き関数と同様、無名関数にもいくつでも式を含めることができます。 関数の戻り値は、最後の式の結果です。

上記の例では、stringLengthFunc に、String を入力とし、入力 String の長さを Int 型の出力として返す無名関数への参照が含まれています。 したがって、関数の型は -> Int と表されます。 しかし、このコードでは関数を呼び出していません。 この関数の結果を取得するには、名前付き関数のように呼び出す必要があります。 StringLengthFunc は、次の例のように String を指定して呼び出す必要があります:

val stringLengthFunc: (String) -> Int = { input ->
 input.length
}
val stringLength: Int = stringLengthFunc("Android")

(高次関数

関数は他の関数を引数に取ることができます。 他の関数を引数に取る関数は高階関数と呼ばれます。 このパターンは、Javaでコールバック・インターフェースを使うのと同じように、コンポーネント間の通信に便利です。

これは高次関数の例です:

fun stringMapper(str: String, mapper: (String) -> Int): Int {
 // Invoke function
 return mapper(str)
}

stringMapper()関数は、Stringと、渡されたStringからInt値を導出する関数を受け取ります。

stringMapper()を呼び出すには、Stringと、その他の入力パラメータを満たす関数、つまり、次の例に示すように、Stringを入力として受け取り、Intを出力する関数を渡します:

stringMapper("Android", { input ->
 input.length
})

無名関数が関数で定義された最後のパラメータである場合、次の例に示すように、関数の呼び出しに使用した括弧の外に渡すことができます:

stringMapper("Android") { input ->
 input.length
}

これまでに述べたすべての型は、Kotlinプログラミング言語に組み込まれています。 独自のカスタム型を追加するには、次の例に示すように、classキーワードを使用してクラスを定義します:

class Car {
 val wheels = listOf<Wheel>()
}

因果性

クラスは状態を表すために属性を使用します。 プロパティはクラスレベルの変数で、ゲッター、セッター、およびバッキング・フィールドを含むことができます。 車を運転するには車輪が必要なので、次の例に示すように、Wheel オブジェクトのリストを Car のプロパティとして追加できます:

val car = Car() // construct a Car
val wheels = car.wheels // retrieve the wheels value from the Car

つまり、LibraryはCarクラスの外部からアクセスすることができ、再割り当てすることはできません。 Carのインスタンスを取得したい場合は、まずコンストラクタを呼び出す必要があります。 そこから、アクセス可能なプロパティにアクセスできます。

class Car(val wheels: List<Wheel>)

ホイールをカスタマイズしたい場合は、クラスのプロパティを初期化する方法を指定するカスタムコンストラクタを定義できます:

 class Car(val wheels: List<Wheel>) {
 private val doorLock: DoorLock = ...
 fun unlockDoor(key: Key): Boolean {
 // Return true if key is valid for door lock, false otherwise
 }
}

上記の例では、クラスのコンストラクタはコンストラクタのパラメータとして List を受け取り、その wheel プロパティをそのパラメータで初期化します。

クラス関数とカプセル化

クラスは振る舞いをモデル化するために関数を使用します。 関数は、公開したいデータだけを公開できるように、状態を変更することができます。 このアクセス制御は、カプセル化と呼ばれるオブジェクト指向の大きな概念の一部です。

以下の例では、doorLock プロパティは、Car クラスの外部すべてに対してプライベートのままです。 車のロックを解除するには、以下の例に示すように、有効なキーを渡して unlockDoor() 関数を呼び出す必要があります:

class Car(val wheels: List<Wheel>) {
 private val doorLock: DoorLock = ...
 val gallonsOfFuelInTank: Int = 15
 private set
 fun unlockDoor(key: Key): Boolean {
 // Return true if key is valid for door lock, false otherwise
 }
}

プロパティの参照方法をカスタマイズしたい場合は、カスタムゲッターとカスタムセッターを提供することができます。 たとえば、あるプロパティのゲッターを公開し、セッターへのアクセスを制限したい場合は、そのセッターをprivateとして指定することができます:


属性と関数の組み合わせにより、あらゆるタイプのオブジェクトをモデル化するクラスを作成できます。

相互運用性

Kotlinの最も重要な特徴の1つは、Javaとのスムーズな相互運用性です。 KotlinコードはJVMバイトコードにコンパイルできるため、KotlinコードはJavaコードを直接呼び出すことができ、その逆も可能です。 これは、Kotlinから既存のJavaライブラリを直接活用できることを意味します。 さらに、ほとんどのAndroid APIはJavaで書かれており、Kotlinから直接呼び出すことができます。

Read next

8周年記念活動ページ作成まとめ

プレビューアドレス: -support...\nそれは非常に単純なアドレス、単純なカットのように見え、その後、いくつかのインターフェイスの要求を終了しますが、実際には、それは多くのことを含む、私は一つずつすることができます!\nコメントボックスカーソル\n顔文字をクリックすると、コメントが

Aug 6, 2020 · 5 min read