Spec-Zone.ru › Qt

Итераторы в Qt по аналогии с Java

Итераторы по аналогии с Java

Для каждого класса контейнера существуют два типа итераторов по аналогии с Java: один для чтения без возможности изменения и один для чтения и записи.

Примечание: Новый код следует использовать итераторы по стандарту STL, так как они более эффективны и могут использоваться совместно с общими алгоритмами Qt и STL generic algorithms.

Контейнеры Итератор для чтения Итератор для чтения и записи
QList<T>, QQueue<T>, QStack<T>, QListIterator<T> QMutableListIterator<T>
QSet<T> QSetIterator<T> QMutableSetIterator<T>
QMap<Key, T>, QMultiMap<Key, T> QMapIterator<Key, T> QMutableMapIterator<Key, T>
QHash<Key, T>, QMultiHash<Key, T> QHashIterator<Key, T> QMutableHashIterator<Key, T>

В этом обсуждении мы сосредоточимся на QList и QMap. Типы итераторов для QSet имеют точно такой же интерфейс, как и итераторы QList; аналогично, типы итераторов для QHash имеют тот же интерфейс, что и итераторы QMap.

В отличие от итераторов по стандарту STL, итераторы по аналогии с Java указывают между элементами, а не непосредственно на элементы. По этой причине они указывают либо в самом начале контейнера (перед первым элементом), в самом конце контейнера (после последнего элемента), или между двумя элементами. Диаграмма ниже показывает допустимые позиции итераторов красными стрелками для списка, содержащего четыре элемента:

Вот типичный цикл для перебора всех элементов QList<QString> в порядке и вывода их в консоль:

QList<QString> list;
list << "A" << "B" << "C" << "D";

QListIterator<QString> i(list);
while (i.hasNext())
    qDebug() << i.next();

Он работает следующим образом: QList, по которому мы хотим выполнить итерацию, передается в конструктор QListIterator. В этот момент итератор находится перед первым элементом в списке (перед элементом "A"). Затем мы вызываем hasNext() для проверки наличия элемента после итератора. Если есть, мы вызываем next() для перехода к этому элементу. Функция next() возвращает элемент, над которым она переходит. Для QList<QString> этот элемент имеет тип QString.

Вот как выполнить итерацию в обратном порядке по QList:

QListIterator<QString> i(list);
i.toBack();
while (i.hasPrevious())
    qDebug() << i.previous();

Код симметричен итерации вперёд, за исключением того, что мы начинаем с вызова toBack() для перемещения итератора после последнего элемента в списке.

Диаграмма ниже иллюстрирует эффект вызова next() и previous() для итератора:

В следующей таблице обобщены функции API QListIterator:

Функция Поведение
toFront() Перемещает итератор в начало списка (перед первым элементом)
toBack() Перемещает итератор в конец списка (после последнего элемента)
hasNext() Возвращает true, если итератор не находится в конце списка
next() Возвращает следующий элемент и перемещает итератор на одну позицию вперёд
peekNext() Возвращает следующий элемент без перемещения итератора
hasPrevious() Возвращает true, если итератор не находится в начале списка
previous() Возвращает предыдущий элемент и перемещает итератор на одну позицию назад
peekPrevious() Возвращает предыдущий элемент без перемещения итератора

QListIterator не предоставляет функций для вставки или удаления элементов из списка во время итерации. Для этого нужно использовать QMutableListIterator. Вот пример, где мы удаляем все нечётные числа из QList<int> с помощью QMutableListIterator:

QMutableListIterator<int> i(list);
while (i.hasNext()) {
    if (i.next() % 2 != 0)
        i.remove();
}

Вызов next() в цикле выполняется каждый раз. Он переходит к следующему элементу в списке. Функция remove() удаляет последний элемент, на котором мы только что перешли. Вызов remove() не делает итератор недействительным, поэтому его безопасно продолжать использовать. Это работает точно так же при итерации в обратном порядке:

QMutableListIterator<int> i(list);
i.toBack();
while (i.hasPrevious()) {
    if (i.previous() % 2 != 0)
        i.remove();
}

Если нам нужно просто изменить значение существующего элемента, мы можем использовать setValue(). В коде ниже мы заменяем любое значение, большее 128, на 128:

QMutableListIterator<int> i(list);
while (i.hasNext()) {
    if (i.next() > 128)
        i.setValue(128);
}

Так же, как и remove(), функция setValue() работает с последним элементом, на котором мы только что перешли. Если мы выполняем итерацию вперёд, это элемент, непосредственно перед итератором; если мы выполняем итерацию назад, это элемент, непосредственно после итератора.

Функция next() возвращает неконстантную ссылку на элемент в списке. Для простых операций нам даже не нужен setValue():

QMutableListIterator<int> i(list);
while (i.hasNext())
    i.next() *= 2;

Как упоминалось выше, классы итераторов QSet имеют точно такой же API, как и у QList. Теперь мы перейдём к QMapIterator, который несколько отличается, поскольку итерация выполняется по парам (ключ, значение).

Как и QListIterator, QMapIterator предоставляет toFront(), toBack(), hasNext(), next(), peekNext(), hasPrevious(), previous() и peekPrevious(). Компоненты ключ и значение извлекаются путём вызова key() и value() на объекте, возвращаемом функциями next(), peekNext(), previous() или peekPrevious().

Следующий пример удаляет все пары (столица, страна), где название столицы заканчивается на «Город»:

QMap<QString, QString> map;
map.insert("Paris", "France");
map.insert("Guatemala City", "Guatemala");
map.insert("Mexico City", "Mexico");
map.insert("Moscow", "Russia");
...

QMutableMapIterator<QString, QString> i(map);
while (i.hasNext()) {
    if (i.next().key().endsWith("City"))
        i.remove();
}

QMapIterator также предоставляет функции key() и value(), которые работают непосредственно с итератором и возвращают ключ и значение последнего элемента, над которым итератор перешёл. Например, следующий код копирует содержимое QMap в QHash:

QMap<int, QWidget *> map;
QHash<int, QWidget *> hash;

QMapIterator<int, QWidget *> i(map);
while (i.hasNext()) {
    i.next();
    hash.insert(i.key(), i.value());
}

Если мы хотим перебрать все элементы с одинаковым значением, мы можем использовать findNext() или findPrevious(). Вот пример, где мы удаляем все элементы с определённым значением:

QMutableMapIterator<int, QWidget *> i(map);
while (i.findNext(widget))
    i.remove();

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/java-style-iterators.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API