気軽に楽しくプログラムと遊ぶ

自分が興味があってためになるかもって思う情報を提供しています。

Kotlin 基礎学習

Kotlin とは?

  • 型推論のある静的型付けのOBJ指向言語
  • Javaとの連携が言語仕様に存在。KotlinからJavaのクラスやメソッドを呼べたりもする

オンライン実行環境

以下の本家サイトの実行環境で、実際に試しながら学習を進めると捗ります。

Kotlin Playground: Edit, Run, Share Kotlin Code Online

Javaとの違い

  • 文末のセミコロンが不要
    • 参照型しかない 。プリミティブ型はない
    • val:読み出しのみ、var:読み書き可
  • 定数:const。const val MAX_NUM = 10

null関係

nullチェックなしコードはコンパイル時にエラー

// non-null type
var a: String = "moji"
a = null // コンパイルエラー

// null type
var a: String? = "moji"
a = null // エラーにならない

nullじゃないとき実行する

var str: String? = null // null typeにnull挿入
str?.split(",") // strがnullじゃないときだけsplit

nullじゃないとき値設定(エルビス演算子)

Company.setName(name?: "ななしの会社")

スコープ関数

// hogeがnullでないときのみ{}の処理を実行させる関数
hoge?.let { 
    textView.text = it.name
}

他にrun, also, applyなどが存在。おいおい理解していく。

演算子

値比較、参照比較

val value1 = "a"
val value2 = "b"
if (value1 == value2) // 値比較で false。否定は !=

var list1 = listOf(1,2,3)
var list2 = listOf(1,2,3)
if (list1 === list2) // true =が3つ。javaは== だったので間違えないように

文字列

文字列中に埋め込み文字

var shopName: String = "sevene"
println("${shopName}")
println("$shopName") // 型推論可能な場合は{}は省略可能

改行入り文字列

行頭の| は目印の記号。trimMarginで除去可能

fun main(args: Array<String>) {
    var strStory = """
           |本日は
           |晴天なり
           |明日もそうなる
           """.trimMargin() 
 
    println("$strStory")
}

キャスト

val hoge = obj as Hoge // objをHoge型に変換する

関数 function

基本の書き方

fun strConbine(a: String, b: String): String {
    return a + b
}

fun strConbine(a: String, b: String): = return a + b
    
fun strConbine(a: String, b: String): Unite {  // Unite はJavaのvoid。省略可
    println(a + b)
}

名前付き引数

引数が多いかつ、同じ型の場合、どの項目に設定しているのか間違えやすい場合がある
その場合に値設定時にあえて関数側の引数名をあえて指定して関数を呼び出す書き方です。
JavaではBuilderパターンを使って回避したりするが、いかんせんコード量が増えがち。

class Book(
    val title: String,
    val price: Int,
    val author: String,
    val isbn: String,
    val remarks: String
) {
    override fun toString(): String {
        return "Book(title='$title', price=$price, author='$author', isbn='$isbn', remarks='$remarks')"
    }
}

呼び出し側のコードは以下です。

val book = Book(
    title = "Kotlinイン・アクション",
    price = 4115,
    author = "Dmitry Jemerov",
    isbn = "978-4839961749",
    remarks = "サイズ: 23.6x18.2x3.6 cm")

println(book)

関数オブジェクト

fun main() {
    val function = ::func
    println( function() )

    val function2: () -> String = ::func // 型を明示する書き方
    println( function2() )
}

fun func(): String {
    return "test"
}

ラムダ式

fun main() {
    // ラムダ式、記述省略なし。=の前が型(ラムダ)、後が関数。関数の ->の前が引数、後が処理
    val square: (Int) -> Int = { i: Int -> i * i }  
    val square2: (Int) -> Int = { i -> i * i }      // 関数内の引数を型推論
    val square3 = { i:Int -> i * i }                // 関数の型を型推論
    val square4: (Int) -> Int = { it * it }         // 引数が1つの場合はitの名で変数が使える。引数部分も省略
}

制御文

if

// ifは式として書ける。ブロックの最後の式が値になる。
val max = if (a > b) {
    print("Choose a")
    a
} else { //この場合、elseがないとエラーになる。返却する値の型はif側と合わせる必要がある
    print("Choose b")
    b
}

for

// インデックス
for (i in array.indices)
    print(array[i])

// インデックスと値
for ((index, value) in array.withIndex()) {
    println("the element at $index is $value")
}

// null考慮
for (i in list.orEmpty())  {
}

while

while (x > 0) {

}

配列、コレクション

配列

val list = arrayOf(1, 2, 3)               // 型類推
val list = intArrayOf(1, 2, 3)            // int指定

println(list[0])      // 要素アクセス

for(item in list){   // ループ
    println(item)
}

コレクション

//. リスト(要素は重複あり)
val list = listOf(1, 2, 3) // 変更不可
val list = mutableListOf(1, 2, 3) // 変更可
val list = mutableListOf<TMP>() // 空で初期化

// Set(重複なし)
val list = setOf(1, 2, 2, 3)  // 変更不可、変更時はmutableSetOf

// Map
val map = mapOf(    // 変更不可、変更時はmutableMapOf
    1 to "one",
    2 to "two",
    3 to "three"
)

for(item in map)
    println("${item.key} to ${item.value}")

for((key, value) in map)
    println("${key} to ${value}")

クラス

データクラス

データのみを保持するクラスは、classの前にdataを付与して宣言

// 定義
data class User(val name: String = "", val age: Int = 0)

// 初期化
val jack = User(name = "Jack", age = 1)  // 名前付き引数
val olderJack = jack.copy(age = 2)       // OBJのコピー&一部書き換え
val jane = User("Jane", 35)  // 通常初期化

// 参照
val (name, age) = jane       // 要素複数Get、nameやageを後続で参照可能

// 定義&コンストラクタ
data class User(val name: String = "", val age: Int = 0) {
        constructor(name: String, age: Int, email: String) : this(name, age)
}

コンパニオンオブジェクト

class MyClass {
    // コンパニオンオブジェクトは1クラスに1つだけ定義可能
    companion object { 
        const val FREE_PRICE = 0
        fun hello(greeting: String) { println(greeting) }
    }
    // companion object myCompanion { } 別名付与も可能

   // objectならば、1クラスに複数定義可能
  object {}
}

fun MyClass.Companion.foo() {
    println("hoge")
}

fun main(args: Array<String>) {
    MyClass.Companion.foo()
    MyClass.foo() // Companionを省略する方が一般的
}

通常クラス

class Hoge {
    // プロパティの定義。getterとsetterが定義される。valならgetterのみ
    var name: String = ""

    // コンストラクタ
    constructor(name: String) {
        this.name = name
    }

    // メソッドの定義
    fun printMethod(strPrint: String) {
        println(strPrint)
    }
}

プライマリコンストラク

// クラスの引数に直接値を渡して初期化するタイプのコンストラクタ
class Hoge(n: String) {
    val name = n
}

// クラスの引数に直接値を渡して初期化するタイプのコンストラクタ、プロパティーも同時に定義
class Hoge(val name: String) {
}

継承

// openをつけると継承可能となる
open class Base {
}

class Hoge : Base() {
}

インターフェース

interface Hoge {
    fun hoge()
}

// 継承と同じ書き方になる
class Sample: Hoge {
    override fun hoge() { // 実装クラスはoverrideを付与
        println("hogehoge")
    }
}

// 無名クラスでインターフェースを実装
class Sample {
    private val h = object: Hoge { // 無名クラス(object)にHogeを実装(具象化)する
        override fun hoge() {
            println("hogehoge")
        }
    }
}