openlang

Присваивать переменной результат void функции?

Почему это принимается?

const std = @import("std");

pub fn main() !void {
    const outcome =
        std.debug.print("Hello, world\n", .{});
    _ = outcome;
}

Результат std.debug.print() имеет тип void, но присваивание этого результата переменной outcome не вызывает никаких возражений у Zig.

Я столкнулся с этим, работая над проектом, когда ошибочно решил, что API сторонней библиотеки возвращает значение, хотя на самом деле его не было. В конце концов попытка отформатировать результат в строку через {s} вызвала ошибку компилятора, но добраться от неё до исходного неверного предположения удалось не сразу.

В каких случаях хранить void в переменной бывает полезно?

Переведено с английскогоПоказать оригинал

Разговор продолжается 4

Следуя доводам
  1. Ссылка на ответ

    Это упрощает код, в котором наличие значения вообще определяется на этапе comptime.

    Вместо разбора типа функции, возможно через несколько слоёв объединений ошибок, гораздо проще проверить тип переменной, которой присвоен результат, и здесь это удобно.

    Кроме того, вызов может быть нужен в любом случае, если функция выполняет другую работу.

    Разрешить значение, которое больше ничем не полезно, не так уж вредно.

    Переведено с английскогоПоказать оригинал
  2. Ссылка на ответ

    Эти сведения не обязаны существовать, потому что некоторые выражения вообще их не предоставляют: например, присваивание в _ ничего не сообщает о типе выражения и не задаёт конкретного места в памяти, куда следует поместить его результат.

    Result Location Semantic (https://ziglang.org/documentation/master/#Result-Location-Semantics)

    Переведено с английскогоПоказать оригинал
  3. Ссылка на ответ

    Мне интересно, какие элементы нужно «отбрасывать» внутри блока test и в каких случаях? Например, в конце исходного кода модуля std.zig находится следующее:

    test {
        _ = Ast;
        _ = AstRlAnnotate;
        _ = BuiltinFn;
        _ = Client;
        _ = ErrorBundle;
        _ = LibCDirs;
        _ = LibCInstallation;
        _ = Server;
        _ = TokenSmith;
        _ = WindowsSdk;
        _ = number_literal;
        _ = primitives;
        _ = string_literal;
        _ = system;
        _ = target;
        _ = c_translation;
        _ = llvm;
        _ = @import("zig/parser_fuzz.zig");
    }

    Если это библиотека, нужно ли помещать туда каждый импортированный модуль? Если нет, то каким модулям нужна такая обработка?

    Переведено с английскогоПоказать оригинал
  4. Ссылка на ответ

    Если это библиотека, нужно ли помещать туда каждый импортированный модуль? Если нет, то каким модулям нужна такая обработка?

    Неявно запускаются только тесты корневого файла, поэтому для остальных файлов/модулей/пространств имён нужна ссылка на пространство имён, содержащее тесты. То же касается struct/union/enum с тестами внутри самого корневого файла, на каждое из них тоже нужна ссылка.

    Для ясности, обращение к sample.member ссылается лишь на sample.member, а не на sample, тогда как _ = sample ссылается на само sample.

    Переведено с английскогоПоказать оригинал

Другие стороны того же вопроса

  1. Как унаследовать класс внутри другого класса?

    Здравствуйте, В пакете, код которого я не могу менять, есть такая иерархия классов: Я хочу добавить удобную обёртку вокруг In…

    Ответы 1Последняя активность scala
  2. Сравнение привязок have и let в Lean4

    Я заметил, что эти два выражения и ведут себя одинаково. То же происходит при доказательстве теорем. Они взаимозаменяемы? В ч…

    Ответы 3Последняя активность lean-4
  3. Инициализация TypeScript Map со значениями в виде массивов строк

    Создаю Map, в котором каждая запись содержит массив строк. Как одновременно задать его тип и инициализировать одним выражение…

    Ответы 2Последняя активность typescript