Шаг 112.
Основы Kotlin.
Списки и множества. Изменение содержимого списка

    На этом шаге мы рассмотрим способы изменения содержимогосписка.

    Если посетитель пришел или ушел в середине ночи, внимательный трактирщик должен добавить или убрать имя посетителя из переменной patronList. В настоящее время это невозможно.

    Функция listOf() возвращает список, доступный только для чтения, в котором нельзя менять содержимое: вы не сможете добавить, убрать, обновить или заменить данные. Доступные только для чтения списки - хорошее решение, потому что они предотвращают досадные ошибки, например, возможность выгнать посетителя на улицу, убрав его имя из списка случайно.

    Природа доступа только для чтения у списка не имеет ничего общего с ключевым словом val или var, использованным для объявления переменной списка. Заменив в объявлении переменной patronList c val (как сейчас) на var, вы не сделаете список доступным для изменения. Вам просто будет разрешено присвоить переменной patronList другое значение, то есть создать новый список.

    Возможность изменять список напрямую зависит от его типа, который и определяет возможность изменять элементы в списке. Поскольку посетители постоянно приходят и уходят, мы должны изменить тип patronList, чтобы разрешить обновление. В языке Kotlin модифицируемый список известен как изменяемый список, и вы должны вызвать функцию mutableListOf(), чтобы его создать.

    Измените код Tavern.kt и используйте mutableListOf() вместо listOf(). Изменяемые списки поддерживают множество функций для добавления, удаления и обновления содержимого. Смоделируйте приход и уход нескольких посетителей, использовав функции add() и remove().

import kotlin.math.roundToInt

const val TAVERN_NAME = "Taernyl's Folly"

var playerGold = 10
var playerSilver = 10
val patronList = mutableListOf("Eli", "Mordoc", "Sophie")

fun main() {
    .    .   .   .
    placeOrder("shandy,Dragon's Breath,5.91")
    println(patronList)
    patronList.remove("Eli")
    patronList.add("Alex")
    println(patronList)
}
.   .   .   .
Файл с проектом можно взять здесь.


Рис.1. Создание изменяемого списка посетителей (Tavern.kt)

    Запустите Tavern.kt. В консоли появится следующее сообщение:

  Madrigal exclaims Ah, d3l1c10|_|s Dr4g0n's Br34th!
  [Eli, Mordoc, Sophie]
  [Mordoc, Sophie, Alex]


Рис.2. Результат работы приложения

    Возможность изменять список напрямую зависит от его типа, который и определяет возможность изменять элементы в списке. Если нужно изменить элементы в списке, используйте MutableList. В противном случае хорошим решением будет запретить изменяемость, используя обычный список.

    Обратите внимание, что новый элемент был добавлен в конец списка. Можно добавить посетителя в конкретное место списка. Например, если VIP-гость придет в таверну, трактирщик может отдать ему предпочтение в очереди.

    Добавьте VIP-гостя - пусть это будет посетитель с таким же именем Алекс (Alex) - в начало списка посетителей. (Алекс хорошо известен в городе и пользуется такими привилегиями, как покупка пинты Dragon's Breath раньше всех остальных, что, конечно, не нравится другому Алексу.) Список может содержать несколько элементов с одинаковым значением, как, например, два посетителя с одинаковыми именами, поэтому добавление еще одного Алекса - это не проблема для списка.

.   .   .   .
fun main() {
    .    .   .   .
    placeOrder("shandy,Dragon's Breath,5.91")
    println(patronList)
    patronList.remove("Eli")
    patronList.add("Alex")
    patronList.add(0, "Alex")
    println(patronList)
}
.   .   .   .
Файл с проектом можно взять здесь.


Рис.3. Добавление еще одного Alex (Tavern.kt)

    Запустите Tavern.kt снова. Вы увидите следующий вывод:

  [Eli, Mordoc, Sophie]
  [Alex, Mordoc, Sophie, Alex]


Рис.4. Результат работы приложения

    Чтобы сделать список patronList изменяемым, нам пришлось заменить в своем коде listOf() на mutableListOf(). Но List имеет функции, позволяющие превращать неизменяемые списки в изменяемые и обратно прямо в процессе выполнения: toList() и toMutableList(). Например, снова сделайте изменяемый patronList() доступным только для чтения, используя toList():

val patronList = mutablelistOf("Eli", "Mordoc", "Sophie")
val readOnlyPatronList = patronList.toList()

    Допустим, популярный Alex решил сменить имя на Alexis. Исполнить его желание можно, изменив patronList при помощи оператора присваивания ([]=), то есть присвоив строке с первым индексом новое значение.

.   .   .   .
fun main() {
    .    .   .   .
    placeOrder("shandy,Dragon's Breath,5.91")
    println(patronList)
    patronList.remove("Eli")
    patronList.add("Alex")
    patronList.add(0, "Alex")
    patronList[0] = "Alexis"
    println(patronList)
}
.   .   .   .
Файл с проектом можно взять здесь.


Рис.5. Модифицирование изменяемого списка с помощью оператора присваивания (Tavern.kt)

    Запустите Tavern.kt. Вы увидите, что patronList обновился и содержит новое имя Alexis.

  [Eli, Mordoc, Sophie]
  [Alexis, Mordoc, Sophie, Alex]


Рис.6. Результат работы приложения

    Функции, которые изменяют содержимое изменяемых списков, называют мутаторами. В таблице 1 перечислены самые распространенные мутаторы для списков.

Таблица 1. Мутаторы изменяемых списков
Функция Описание Примеры
[]= (оператор присваивания) Присваивает значение по индексу; возбуждает исключение, если индекс не существует val patronList = mutableListOf("Eli", "Mordoc", "Sophie")
patronList[4] = "Reggie"
IndexOutOfBoundsException
add Добавляет элемент в конец списка, увеличивая размер на один элемент val patronList = mutableListOf("Eli", "Mordoc", "Sophie")
patronList.add("Reggie")
[Eli, Mordoc, Sophie, Reggie]
patronList.size
4
add (по индексу) Добавляет элемент в список по индексу, увеличивая размер на один элемент. Возбуждает исключение, если индекс не существует val patronList = mutableListOf("Eli", "Mordoc", "Sophie")
patronList.add(0, "Reggie")
[Reggie, Eli, Mordoc, Sophie]
patronList.add(5, "Sophie")
IndexOutOfBoundsException
addAll Добавляет все элементы из другой коллекции, если они того же типа val patronList = mutableListOf("Eli", "Mordoc", "Sophie")
patronList.addAll(listOf("Reginald", "Alex"))
[Eli, Mordoc, Sophie, Reginald, Alex]
+= (оператор сложения с присваиванием) Добавляет элемент или коллекцию элементов в список mutableListOf("Eli", "Mordoc", "Sophie") += "Reginald"
[Eli, Mordoc, Sophie, Reginald]
mutableListOf("Eli", "Mordoc", "Sophie") += listOf("Alex", "Shruti")
[Eli, Mordoc, Sophie, Alex, Shruti]
-= (оператор вычитания с присваиванием) Удаляет элемент или коллекцию элементов из списка mutableListOf("Eli", "Mordoc", "Sophie") -= "Eli"
[Mordoc, Sophie]
val patronList = mutableListOf("Eli", "Mordoc", "Sophie")
patronList -= listOf("Eli", Mordoc")
[Sophie]
clear Удаляет все элементы из списка mutableListOf("Eli", "Mordoc", Sophie").clear()
[]
removeIf Удаляет все элементы из списка, которые удовлетворяют условию в лямбде val patronList = mutableListOf("Eli", "Mordoc", "Sophie")
patronList.removeIf { it.contains("o") }
[Eli]

    На следующем шаге мы рассмотрим итерацию.




Предыдущий шаг Содержание Следующий шаг