お茶漬けびより

"あなたに教わったことを、噛んでいるのですよ" 五等分の花嫁 7巻 「最後の試験が五月の場合」より

Kotlin 勉強メモ(Kotlin 入門までの助走読本)

まちカドまぞく面白いです。二回見る程度には面白いです。

最近、Android 開発できるようになろうとチマチマ勉強中です。過去に一度か二度勉強したのですが途中で挫折しました。でも今回は少しずつですが理解が進んでいる気がします。

Android 開発では、今や開発言語は Kotlin です。Android 開発しているのに Kotlin 知らない人なんていません。GoogleAPI の提供を Kotlin 優先にするって言ってます。

jp.techcrunch.com

だから Kotlin を勉強しています。

というのもありますが、単純に書いてて楽しいです。Kotlin

(もちろん、Android 開発は必ず Kotlin でするべきということではありません。環境によりけりです)

参考書籍

Kotlin を勉強するにあたって参考にした書籍は Kotlin 入門までの助走読本です。

drive.google.com

プログラミング経験者が Kotlin を学ぶのに最適な本です。あまり詳細に踏み込まず、かといって浅すぎない。Kotlin がどんな言語かなんとなく理解できる良い本です。

過去に速習 Kotlin という本も読んだことがありますが、これよりも浅いように感じました。ただ、助走読本のほうは、Java からの移行や今後どうやって Kotlin を取り入れるかなどの情報もあるのでどちらの方が良いというのは決められないです。

速習 Kotlin: Javaより簡単!新Android開発言語を今すぐマスター 速習シリーズ

速習 Kotlin: Javaより簡単!新Android開発言語を今すぐマスター 速習シリーズ

まだ読んでいませんが、さらに Kotlin を知るなら Kotlin イン・アクションは必読だと思います。

Kotlinイン・アクション

Kotlinイン・アクション

今回は、Kotlin 入門までの助走読本 を読んでメモしたことを羅列していきます。

はじめに

Kotlin の環境構築は IntelliJ IDEA をいれれば済むはずですが、それも面倒な場合、とにかく1秒でも早く実行したいという人は、Kotlin Playground(正式名称わかりません) がオススメです。

play.kotlinlang.org

www.jetbrains.com

Kotlin Playground は、オススメですがたまに全然動かなくなります(実行しすぎ?)。片手間に IntelliJ IDEA を入れるのをオススメします。

(?)がついている箇所は深く検証していなくて不明確な部分です。

以下、Kotlin 入門までの助走読本のメモです。

変数

val, var で宣言します。

  • val は変数の再代入が不可
  • var は変数の再代入が可
  • 型は省略可能
 val num = 1 // val num: Int = 1 と同じ
 num = 2 // コンパイルエラー
 var num2: Int = 2
 num2 = 4 // 可能

if 式

式としても文としても書けます。

val value = if (true) { 32 } else { 64 } // value = 32

when 式

switch のように書けます。

  • else がないとコンパイルエラーになる
  • 左辺(左側)でも使える
val str = when (1) {
  1 -> "one"
  2 -> "two"
  else -> "other"
} // str = "one"

for 文

for (i in 0..2) {
  print(i)
 } // 012

downTo を使うと逆順になります

for (i in 2 downTo 0) {
  print(i)
} // 210

step を使うとその値で飛ばします(downTo でも使えます)

for (i in 0..2 step 2) {
  print(i)
 } // 02
  • while, do-while もある

コレクション

  • reversed で逆順になる
  • reversedreversedArray は、 List で返すか、Array で返すかの違い(基本は reversed で返す)
  • ミュータブル読み取り専用がある。基本は読み取り専用
    • 読み取り専用であって、イミュータブルではない
  • 生成はファクトリ関数を使う
  • forEach を使う場合、it で要素にアクセスできる

以下が詳しいです。

qiita.com

null 許容型

型宣言で ? を使うことで null 許容型になります。デフォルトは null 非許容です

  • ?.エルビス演算子) を使うと null じゃないときに処理を行う。
    • このとき、渡す値として使うと null のときは、null が返る
val str: String? = null
val value2 = str?.length // null が渡る
println(value2) // null が出力される
  • 値を渡す場合、受け取る側も null 許容型でないといけない
    • null チェックが行われても型は変わらない(null 許容型のまま)
      • ただし、null チェックのブロック内では、null 非許容型として扱える
        • null の代入は可能

!! 演算子

  • null 許容型非許容型に強制変換するが、危険
  • requireNotNull 関数を検討すること

関数

fun double(a: Int): Int {
  return a * 2
} // double(2) == 4
  • 引数は val なので(?)、再代入が不可
fun double(a: Int): Int {
  a = 0 // コンパイルエラー
  return a * 2  
}

以下の書き方も可能です。

fun double(a: Int): Int = a * 2
  • 戻り値の型が定義されていない場合、Unit 型になる
  • 戻り値がある場合、型推論が可能なら省略可能
fun double(a: Int) = a * 2 // 戻り値の型は Int
fun double(a: Int) = a * 2.0 // 戻り値の型は Double
  • デフォルト値が書ける
fun double(a: Int = 0) = a * 2 // double() == 0
  • 引数名を指定すると順不同で書ける
fun multiple(a: Int, b: Int) = a * b
val c = multiple(b = 2, a = 4) // c == 8
  • 型パラメータを使える
fun<T> toString(a: T): String = "$a"

ラムダ式

val a = {a: Int -> a * 2}
println(a(2)) // 4

次のようにも書けます。

val a : (Int) -> Int = {a -> a * 2}
  • デフォルト引数は使えない(?)
  • ラムダ式をその場で実行できる
  • 引数なしの場合、-> の左側は何も書かない
println({ -> "Hello World!"}()) // Hello World!

高階関数

引数と戻り値の型に関数が指定できます。

fun execute(a: (Int)->Int): Int {
  return a(4)
}
val func = {a: Int -> a * 2}
println(execute(func)) // 8
fun execute(a: Int): (Int) -> Int {
  return {a: Int -> a * 4}
}
println(execute(2)(3))

上記の例はあまり意味がありませんが、例えばロック処理を行うようなときに使えるようです。

クラス

class MyClass {}
class MyClass // 同じ意味
val c = MyClass()
  • 明示的なコンストラクタの定義
class MyClass(v: Int) {}

上記の場合、vMyClass が持つプロパティにはなりません(コンストラクタ内でしか使えない)。

 class MyClass(v: Int) {
   val value = v
 } // v は、メンバの初期化にしか使えない
  • val, var をつけるとプロパティを定義できる
 class MyClass(val value: Int) {
   fun printValue() = println(value)
 }
  • init でイニシャライザを作れる
class MyClass(var value: Int) {
  init {
    value = 0
  }
  fun printValue() = println(value)
} // コンストラクタで数値を入れても init で初期化される
  • デフォルト引数が使える(関数と同じなので、コードは省略)
  • セカンダリコンストラクタを定義する場合、 constructor キーワードを使う
class MyClass() {
  constructor(v: Int) : this() {
    print("Secondary")
  }
} // MyClass(10) のようにするとセカンダリが呼ばれる
  • セカンダリではプロパティを定義できない
  • this は必須。プライマリコンストラクタを呼び出している

  • アノテーションや可視性修飾子をつける場合、constructor キーワードをつける(?)

    • 可視性はなくても付けられる(?)
  • メソッドは、クラス内部で関数のように定義する

class MyClass(val value: Int) {
  fun printValue() = println(value)
} // MyClass().printValue()

プロパティ

  • val で定義すると読み取り専用になる(getter)
  • var で定義すると読み取り書き込み可能になる(getter, setter)

次のように呼び出します。

class MyClass(v: Int = 10) {    
  val value: Int = v
 } // MyClass().value で呼び出せる
  • get, set は自分で作れる
class MyClass(v: Int = 10) {    
  var value: Int
  get() {
    println("Called GetValue")
    return 100
  }
  set(v: Int) {
    println("No Set")
  }
}
  • get, set 内でそのプロパティにアクセスすると無限ループするので注意
  • プロパティにアクセスしたい場合、(罰金)バッキングフィールド field を使う
  • get のアクセス修飾子は、プロパティと同じにしないといけない
  • set のアクセス修飾子は、異なる修飾子を指定できる
class MyClass(n: String = "") {
  private var name = n
    get() {
      return field
    }
    private set(value) {
      field = value
    }
}

可視性修飾子

public

  • デフォルト
  • どこからでもアクセス可能

internal

  • 同一モジュール内のみアクセス可能
  • コンパイル単位、Maven や Gradle のプロジェクト単位

protected

  • 同一クラス内とサブクラス内からアクセス可能

private

  • 同一クラスのみアクセス可能

オブジェクト(詳細は割愛)

  • class ではなく、object キーワードを使う。
  • シングルトンになる

コンパニオンオブジェクト(詳細は割愛)

  • Kotlin は static なメンバを定義できない
  • コンパニオンオブジェクトはその代わり

データクラス(詳細は割愛)

  • データを保持するためだけのクラス

継承

  • クラスはデフォルトでは継承できない
  • open 修飾子をつけると継承できるようになる
open class MyClass()
class ExMyClass(): MyClass()
  • 多重継承はできない
  • オーバライドする場合、元のメソッドをオーバライド可能にする必要がある(open 修飾子をつける)
  • オーバライドする側は、override をつける
open class MyClass() {
  open fun print() = println("MyClass")
}
class ExMyClass(): MyClass() {
  override fun print() = println("ExMyClass")
}

インタフェース

  • interface キーワードを使う
interface MyInterface {
  val value: Int
  fun print() = println("MyInterface")
} // プロパティも定義できる

open class MyClass(): MyInterface {
  override var value = 10
  override fun print() = println("MyClass")
}
  • プロパティも定義できるが、継承先で必ず初期化しないといけない
  • インタフェースをインタフェースに継承できる
interface ExMyInterface : MyInterface {
  override fun print() = println("ExMyInterface")
}
  • object: 式で匿名クラスを作れる
interface MyInterface {
  val value: Int
  fun print() = println("MyInterface")
  fun printValue() = println(value)
}

interface ExMyInterface : MyInterface {
  override fun print() = println("ExMyInterface")
}
    
object: ExMyInterface{
  override val value = 10
}.print() // ExMyInterface が出力される

パッケージ(詳細は割愛)

  • Java と同じ機能
package mypackage.myclass
class MyClass
  • import でアクセスできるようになる

アクセス制限

public

  • どこからでもアクセス可能
  • デフォルト

internal

  • 同一モジュール内でアクセス可能
  • コンパイル単位、Maven や Gradle のプロジェクト単位

private

  • 同一ファイル内のみ可能

その他