【Kotlin】参照渡しと値渡しの違いと注意点!変数とデータの取り扱い
この記事からわかること
- Kotlinの基本構文
- 変数のデータの受け渡し
- 参照渡しと値渡しの違い
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
Kotlinでのデータの渡し方の違い
Kotlinではデータ型の種類によってデータの渡され方が異なります。いわゆるオブジェクト(クラスインスタンスや配列など)は参照渡し、プリミティブ型(Int, Double, Booleanなど)は値渡しになっています。
- オブジェクト(クラスインスタンスや配列など) → 参照渡し
- プリミティブ型(Int, Double, Booleanなど) → 値渡し
両者の違いは渡されるものが異なります。
参照渡し
データが格納されているメモリの参照を渡す
値渡し
データをコピーして渡す
参照渡し
参照渡しはデータが格納されているメモリの参照を渡します。変数などに渡されるのはデータを格納しているメモリの参照なので、originalList
もcopyList
も参照しているデータは同じになります。
そのため以下のように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など)は値渡しになります。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。