ПредишенСледващото

Итераторът в Делфи

казва Документацията. който се поддържа от повторение на масив елементи, символа на ред, на зададените стойности (SET), и най-интересното е, че специално подготвен класове и записи. С масиви и символи на всички очевидни за комплекти може да обясни малко по-подробно:

Това е един пример на типичен използване на повторения над комплекти. Без повторение ще трябва да го направите:

Не само, че е неудобно, ще бъде необходимо, за да добавите нов ред в процедурата всеки път, когато се добавя нов флаг на снимачната площадка.

Сега за най-интересните характеристики на итератори. Позволено, за да създадете свой собствен клас итератори. Например, собствен списък или TStringList може да претърпи се изпълнява за списък. Повечето от стандарта на своите класове и подкрепа:

Подкрепа повторение и да добавите свои собствени клас. За това имаме нужда от помощник клас, итератора (или Enumerator, както искате). Основният клас трябва да има функция GetEnumerator. която създава и връща инстанция на класа на помощник:

Самата итератор трябва да съдържа функция MoveNext за да се върнете на False, ако повече елементи Не имот Актуални, която връща текущия елемент:

Тук е готов да прости на итератор. Не можа ли нещо да се подобри? Например, всеки опитен delfist веднага да забележите, че всяко използване на итератор изисква създаването на даден обект, и създаване на обект, ние си спомняме доста бавна работа. Благодаря на Бог, можем да направим запис итератор. Всичко, което трябва да се промени в нашия код - за отстраняване на повикването към наследствената Създаване:

По този начин ние се доста бързо повторение на произволна контейнер. Можете да се TMyCollection рекорд направи. Специално изпълнение полза, той не ще, тъй като тя е създадена само веднъж, но ако имате нужда от него за други цели - винаги добре дошли. Във всеки случай, си спомням как в Делфи осъществява връзките на кръст. С класа:

Очевидният въпрос е: възможно е да не създават никакъв обект в итерация, или запишете? Не може ли просто да се върна в препратката GetEnumerator към себе си, ако вярваме, че повторение ще се използва само по един?

Правилният отговор е: не, не можеш. Delphi автоматично унищожава Итераторът след употреба. GetEnumerator Ако се върнете на основния обект, той ще бъде унищожен. Да нищо не може да бъде, не може да замени унищожи.

Някой ще попита, възможно ли е да се обърне фокуса от този запис. Records не унищожени? Да, записите не са унищожени, но те са трикове и нямат значение. Не забравяйте, че записите са предават по стойност; Това означава, че функцията за GetEnumerator не се връща позоваване на протокола, както и блок от данни, цялото му съдържание. Можете, разбира се, да се върне на изискуем:

Това ще означава само, че вие ​​сте създатели TMyRecord нов рекорд и го копирайте всички стари съдържание. Този подход, между другото, може да бъде полезно, след като, например, ако във вашия TMyRecord малко количество важна информация. Когато влезете от множество нишки понякога е изгодно да не блокира обекта за срока на действие на итерация и го копирайте за по-късно сортиране, и веднага го освободи.

блокиране
Те бяха просто използване на итератори, а сега да преминем към по-сложни. Най-подходящо да се итератори е, че те позволяват да се изпълни произволен код в момента на преброяването. Това е, което ние използваме. Например, ние правим прекалено много конци-безопасно. Когато се работи с множество потоци от всички програмист повтаря по този начин:

Ние се опрости този дизайн!

Понякога този подход, както вече казах, че е много лесен за използване - но не винаги. Често, за да спаси държавата, която искате да копирате целия масив, макар и указатели, и то е много дълго. Колко жалко, че ние не можем да знаем, когато се разрушава структурата на Delphi ... или не може?

Какво ще правим сега - това е малко магия. Delphi не причинява деструктори за протокола, но тя финализира цялото му съдържание, включително причините _Release интерфейси. Ето защо, ние ще създаде интерфейс, който ще освободи ключалката на _Release.
Първо, трябва неопределена IInterface изпълнение:

RefCnt напуснахме само да не случайно се счупи някаква вътрешна оптимизация на Делфи, който използва тази стойност. Най-общо казано, човек винаги може да се върне единица. Нашата цел не е разрушен от RefCnt падане на нула; живота й е зададен като за нормална Delphi обект, ръчна унищожение. При заснемане препратка към самата тя блокира свирене обект, когато са освободени - отключва.

Сега самата колекция:

Моля, имайте предвид, че ние продължаваме да Gatekeeper като обект. Ако можем да го държат като интерфейс, той постоянно ще остана в капан. "Smart" указатели към интерфейси в Делфи са подредени така, че автоматично да доведе до _AddRef когато определянето на стойност на тип интерфейс, и автоматично да доведе до _Release при изчистването на тази стойност.

Когато ги попитахме TMyCollectionEnumerator, ние използваме този имот, който се върнем итератор, в която ние поставяме променлива от тип IInterface. Когато го поставите в нашия Gatekeeper, Delphi автоматично _AddRef, блокиране колекция. Когато един рекорд е унищожена, Delphi автоматично довършва влизане Gatekeeper изчиства полето, и тъй като това е вид интерфейс, причинявайки му _Release - и колекция от отключена.

Това безспорно е много удобен и бърз начин. Gatekeeper само един тип обект на всяко събиране; можете да го използвате в най-различни итератори директно. Веднъж създаден, когато създавате TMyCollection и почти не добавя отгоре. Все пак, има някои клопки. Въпреки Delphi уверява унищожаването на рекордно итератор, и да го унищожи, като интерфейсът чиста, не е известно кога ще го направи. В прикачения кода, аз извършва някои експерименти и е установено, например, че въпреки че обикновените функции итератор е унищожен веднага след излизане от "за ... в", в основната част на конзолата за кандидатстване итератори-записите не са унищожени най-малко. Така че тази техника трябва да се използва с повишено внимание.

филтри
Друго интересно приложение на итератори - филтри. Вместо на писане:

Бих искал нещо като това:

С итератори е лесно да се направи, обаче, срещу допълнително заплащане - ако използвате записите. Тези допълнителни разходи - за създаването на още един рекорд. I демонстрира:

Проблемът тук е, че синтаксиса на Delphi трудни изисквания към обекта от дясната страна "за ... в" за изпълнение GetEnumerator. Филтър функция, която пишем, трябва само по себе си създава и изведе обект, а след това този обект ще трябва да се създаде друг - Enumerator. Бих искал да бъде в състояние да използва това като Enumerator най създаден FilterKeepalive обект (в края на краищата, това е по-nizachem не е необходимо!). Въпреки това, най-високи резултати, че няма да работят за изложените причини: ако ние просто възстановява в GetEnumerator "Резултат: = Self", ние всъщност копирате записа и не се подобри положението.

Друго нещо - класовете. Там се е наложено без допълнително заплащане:

Клас просто връща препратка към себе си. Ако си спомняте, за да направите това събиране е било забранено, защото Delphi унищожава Итераторът след употреба. Въпреки това, тук не сме само на ръка и е от жизненоважно значение: кой друг ще унищожи създаден FilterKeepalive клас време?

генератори
Друго интересно приложение на итератори, дължащи се на факта, че ние не трябва да се справи със съществуващите съоръжения. Итераторът да превъртите през елементите, изчислени в движение от него. Връзката в примерите имат поколение на числата на Фибоначи, и ние ще се реши практически проблем - и по-бързо (така разбира се, без класи, фабрики и интерфейси, Бог ми забрани).

Нека създадем итератор, който ще ни върне всички прозорци на високо равнище в системата:

Няма проблеми с него, но все пак да ви даде кода. Първо, създаване на самата итератор. Тя е много проста, съдържа целия набор от прозорци намерени и попълнени при създаването на капитана:

Очевидно е, че имаме нужда от една фабрика, която тя създава:

Това е всичко. TopLevelWindows функция връща в завода, без да е необходимо да се направи каквато и да е операции (върна запис се избира автоматично). В съпътстващата програма преминава през всички прозорци и да ги отпечатва на екрана (не крия, не се страхувайте, аз не съм толкова луд).

Послепис Най-общо казано, прозорците не могат да бъдат нарушени,. Конвенционалните масиви работа не е по-лошо:

Е, добре, като - файлове?

Тук също спокойно можете да управлявате масив, но ние пестим на факта, че ако в средната enumeratsii ние искаме да направим почивка - не е извършил ненужни искания до файловата система. Е, в общи, масиви, за пореден път да не се разпределя. Запис за повторение-се разпределя в стека, както аз го разбирам.

Подкрепете проекта - споделете линка, благодаря!