【Kotlin】参照渡しと値渡しの違いと注意点!変数とデータの取り扱い

【Kotlin】参照渡しと値渡しの違いと注意点!変数とデータの取り扱い

この記事からわかること

  • Kotlin基本構文
  • 変数データ受け渡し
  • 参照渡し値渡し違い

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

Kotlinでのデータの渡し方の違い

Kotlinではデータ型の種類によってデータの渡され方が異なります。いわゆるオブジェクト(クラスインスタンスや配列など)は参照渡しプリミティブ型(Int, Double, Booleanなど)は値渡しになっています。

両者の違いは渡されるものが異なります

参照渡し

データが格納されているメモリの参照を渡す

値渡し

データをコピーして渡す

参照渡し

参照渡しはデータが格納されているメモリの参照を渡します。変数などに渡されるのはデータを格納しているメモリの参照なので、originalListcopyListも参照しているデータは同じになります。

そのため以下のようにcopyListに変更を加えても元のデータのメモリ参照を参照しているため変更がoriginalListにも反映されるようになります。(正確にはoriginalListに反映されているというより、同じメモリを参照しているだけです。)

val originalList = mutableListOf("Apple", "Banana", "Cherry")
// メモリの参照をコピー
val copyList = originalList
copyList.add("Orange")

println(originalList) // [Apple, Banana, Cherry, Orange]
println(copyList)     // [Apple, Banana, Cherry, Orange]

Kotlinではオブジェクト(クラスインスタンスや配列など)は参照渡しになります。これは関数の引数に渡した場合も同じです。以下のようにリストの要素の中身を変更するメソッドを用意して呼び出すと元のリストが変更されたことを確認することができます。

data class Person (
    var name: String,
    var age: Int
)
fun main() {
    val people = listOf(
        Person("Ame", 20),
        Person("Kasa", 25),
        Person("Mahiro", 28)
    )

    // メソッドにリストを渡す
    println("Before: $people")
    // Before: [Person(name=Ame, age=20), Person(name=Kasa, age=25), Person(name=Mahiro, age=28)]
    modifyPeople(people)
    
    // 元のリストが変更されたことを確認
    println("After: $people")
    // After: [Person(name=Ame, age=21), Person(name=Kasa, age=26), Person(name=Mahiro, age=29)]
}

// リストの要素を変更するメソッド
fun modifyPeople(people: List<Person>) {
    people.forEach { it.age += 1 }
}

参照渡しのデータを値渡しにする方法

参照渡しで扱われるデータはあまり理解していないと値渡しと勘違いして予期せぬバグを引き起こす可能性があります。参照渡しのデータを値渡しにするには明示的にコピーを生成する必要があります。

独自のクラスを使用する際にdata classを使用することで簡単にコピーを生成できるcopyメソッドが使えるようになります。

おすすめ記事:【Kotlin/Android Studio】data classとは?クラスとの違いと使い方

copyメソッドなどを使用してコピーを生成すれば元のリストに変更を加えずに新規で変更したリストを生成することができます。

data class Person (
    var name: String,
    var age: Int
)
fun main() {
    val people = listOf(
        Person("Ame", 20),
        Person("Kasa", 25),
        Person("Mahiro", 28)
    )

    println("Before: $people")
    // Before: [Person(name=Ame, age=20), Person(name=Kasa, age=25), Person(name=Mahiro, age=28)]
    val copyPeople = modifyPeople(people)
    
    println("After: $people")
    // After: [Person(name=Ame, age=20), Person(name=Kasa, age=25), Person(name=Mahiro, age=28)]
    println("After: $copyPeople")
    // After: [Person(name=Ame, age=21), Person(name=Kasa, age=26), Person(name=Mahiro, age=29)]
}

fun modifyPeople(people: List<Person>): List<Person> {
    // 値をコピーした配列を生成
    val copyList = people.map { it.copy() }
    copyList.forEach { it.age += 1 }
    return copyList
}

値渡し

値渡しはデータをコピーして渡します。変数などに渡されるのは対象のデータのコピーなので変更しても元のデータは変更されません。

fun increment(value: Int): Int {
    return value + 1
}

fun main() {
    val number = 5
    val newNumber = increment(number)
    println(number) // 5
    println(newNumber) // 6
}

Kotlinではプリミティブ型(Int, Double, Booleanなど)は値渡しになります。

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index