Треки
/
Factor
Factor
/
Вправи
/
Стрічка телеграфіста
Стрічка телеграфіста

Стрічка телеграфіста

Навчальна вправа

Вступ

Ми вже використовували потоки в channel-chatter і позбувалися їх у boatswains-bilge. Ця вправа - наш перший власний потік. Це клас, який реалізує протокол, тож той самий код із with-input-stream / read1 / stream-read1, який працював із <string-reader>, працюватиме і з нашим.

Міксини: друга половина ієрархії класів

Ми вже знаємо TUPLE: child < parent … з dragons-descendants: ієрархію з одним батьком, де слоти передаються вниз. У Factor є другий спосіб розширити граф класів: відкриті міксини. MIXIN: m оголошує клас без слотів, до якого інші класи можуть долучитися згодом за допомогою INSTANCE: c m. Належність тут багато-до-багатьох: клас може бути екземпляром стількох міксинів, скількох захоче.

Протокол потоків використовує два міксини, щоб позначити, яку половину інтерфейсу реалізує клас:

INSTANCE: my-stream input-stream    ! readable
INSTANCE: my-stream output-stream   ! writable

Потік може бути одним, іншим або обома. Узагальнені методи на input-stream (або output-stream) тоді спрямовуються до будь-якого класу, що долучився до міксина. Саме так read1, stream-contents, with-input-stream тощо знаходять дорогу до нашого класу.

Міксини відкриті: ми можемо додати нового члена вже після оголошення міксина, навіть в іншому словнику. Це і є контраст із TUPLE: < parent, де відношення фіксується, коли оголошують дочірній клас.

Узагальнені методи протоколу

Узагальнені методи протоколу живуть у io:

stream-read1         ( stream -- elt/f )
stream-read          ( n stream -- seq/f )
stream-read-unsafe   ( n buf stream -- count )
stream-write1        ( elt stream -- )
stream-write         ( seq stream -- )
stream-flush         ( stream -- )
stream-element-type  ( stream -- type )

stream-read1 повертає наступний байт (або f у кінці потоку); stream-write1 записує один. stream-read-unsafe - це низькорівневе пакетне читання, яке надає більшість вхідних потоків; stream-read побудовано поверх нього, і воно подбає про виділення памʼяті. stream-element-type каже, чи потік має справу з байтами (+byte+) чи символами (+character+); коли ми обгортаємо інший потік, найпростіша реалізація просто делегує роботу базовому потоку.

Прибирання надходить із destructors

Потоки - це одноразові обʼєкти: власний потік успадковує disposable і реалізує dispose*. Це той самий механізм із boatswains-bilge, застосований до класу потоку:

TUPLE: my-stream < disposable underlying ;

: <my-stream> ( underlying -- s )
    my-stream new-disposable swap >>underlying ;

M: my-stream dispose* underlying>> dispose ;

Щойно це готово, всі комбінатори with-… із channel-chatter автоматично працюють із нашим потоком.

Вказівки

Ми — телеграфісти бездротового звʼязку на вантажному судні. Сигнал надходить зашумленою лінією (корабельні механізми, атмосферні завади, уривки чужої мови), переплітаючись із тим кодом Морзе, який ми шукаємо. Щоб упіймати повідомлення, ми пропускаємо дріт крізь пристрій-стрічку, який відкидає все, крім дійсних символів коду Морзе (., - і пробіл, що розділяє літери).

Наше завдання — збудувати стрічку як власний вхідний потік Factor.

1. Визначте стрічку

Визначте кортеж tape, який успадковує disposable і містить один слот wire для базового вхідного потоку.

TUPLE: tape < disposable wire ;

Потім напишіть конструктор <tape> ( wire -- tape ). Використайте new-disposable (а не new), щоб framework деструкторів зареєстрував стрічку, і збережіть базовий потік у слоті wire.

2. Долучіть міксин input-stream

Оголосіть tape як input-stream:

INSTANCE: tape input-stream

Завдяки цьому типові комбінатори протоколу звертаються до нашого класу.

3. Прочитайте один символ коду Морзе

Реалізуйте M: tape stream-read1 ( tape -- elt/f ). Читайте байти з базового дроту, доки не натрапите на один із символів CHAR: ., CHAR: - або CHAR: \s (пробіл). Поверніть цей байт. Якщо дріт повертає f (кінець потоку), поверніть і f: стрічка закінчилася.

"x.y -ab cz" <string-reader> <tape>
[ stream-read1 ] [ stream-read1 ] [ stream-read1 ] tri
! => CHAR: . CHAR: - CHAR: \s

4. Делегуйте тип елемента

Реалізуйте M: tape stream-element-type ( tape -- type ), делегувавши роботу дроту: стрічка не змінює тип елементів, які читаються.

5. Приберіть за собою

Реалізуйте M: tape dispose* ( tape -- ). Framework викликає наш метод рівно один раз на кожен dispose; просто звільніть базовий дріт.

Коли ці пʼять частин на місці, стрічка працює як звичайний вхідний потік: with-input-stream, stream-read та інші слова протоколу автоматично звертаються до наших методів.

Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Factor Exercism

Час розпочати Стрічка телеграфіста?

Зареєструйтеся на Exercism, щоб вивчати й опановувати Factor, а також 47 концепцій163 вправи та справжнє наставництво від людей, і все це безкоштовно.