From d773a99ac5c4e12a93effa2c5a642fe583c22145 Mon Sep 17 00:00:00 2001 From: zed Date: Sat, 18 Nov 2023 21:23:08 +0300 Subject: [PATCH] On branch main modified: src/ch08.md --- src/ch08.md | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/ch08.md b/src/ch08.md index d320c99..1e40fd7 100644 --- a/src/ch08.md +++ b/src/ch08.md @@ -357,9 +357,9 @@ ptr_info.Pointer.child.writeAll(self, data); ## Использование маркированных объединений -... - -Вот рабочий полноценный пример: +В качестве более простой альтернативы описанным схемам для эмуляции +интерфейсов можно применять маркированные объединения, вот полноценный +рабочий пример: ```zig const std = @import("std"); @@ -391,3 +391,32 @@ pub fn main() !void { } ``` + +Напомним, что когда в `switch` используется переменная, представляющая +собой маркированное объединение, захваченные значения (в примере +`|file|`) всегда имеют правильный тип (для примера это `File`). + +Минусом такого подхода является то, что нужно заранее знать все возможные +реализации, поэтому он не подходит, например, для создания интерфейсов, +реализации которых могли бы создавать третьи стороны. Каждая возможная +реализация должна быть включена в объединение. + +Если интерфейс используется только внутри какого-то приложения, +это ограничение роли не играет. Вы можете построить, к примеру, +объединение `Cache`, которое будет включать в себя все нужные +реализации, например, `InMemory`, `Redis` и `Postgresql`. Если +появляются новые механизмы, Вы просто обновляете объединение. + +Во многих случаях интерфейс будет вызывать функции с реализациями +непосредственно. Для таких случаев можно использовать специальный +синтаксис, `inline else`: + +```zig +switch (self) { + .null => {}, // do nothing + inline else => |impl| return impl.writeAll(data), +} +``` + +Такой оборот `else` автоматически разворачивается, +то есть для каждого варианта получается правильный тип `impl`.