LINUX.ORG.RU

Ищу аналог union/enum/adt для Python/Go

 , ,


1

2

Интересуют не либы, а идиоматическое решение задачи вида:

Rust:

enum Data {
    Number(u32),
    String(String),
}

let mut items = Vec::new();
items.push(Data::Number(5));
items.push(Data::String("text".to_string()));

for item in items {
    match item {
        Data::Number(n) => println!("Number {}", n),
        Data::String(ref s) => println!("String {}", s),
    }
}

C++:

std::vector<std::variant<int, std::string>> items;
items.push_back(5);
items.push_back("text");

for (const auto &item : items) {
    if (const auto n = std::get_if<int>(&item)) {
        std::cout << "Number " << *n << std::endl;
    } else if (const auto &s = std::get_if<std::string>(&item)) {
        std::cout << "String " << *s << std::endl;
    }
}

Как это повторить на python и go?

То есть нужно заполнить вектор/список/массив объектами разных типов (желательно с гарантиями) и затем пробежаться по ним, забирая значение каждого типа.

★★★★★

Последнее исправление: RazrFalcon (всего исправлений: 1)
Ответ на: комментарий от tailgunner

И всё это ты назвал так, как назвал.

Я это никак не называл.

Хотя, в прошлом сообщении я был не прав — это все-таки не неведомые дали, а как раз самое буквально понимание. Типа если в сообщении написано «тред не про реальный код», то для тебя это значит, что обязательно имеются ввиду все примеры кода выше.

Но нет, товарищ хвостострел — «тред не про реальный код» значит только то, что тогда обсуждение шло в отрыве от задачи.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 2)

Кстати, идиоматичное решение задачи парсинга SVG на Python — это вызов библиотеки на Си.

Такие дела.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

Кстати, идиоматичное решение задачи парсинга SVG на Python — это вызов библиотеки на Си.

Сомневаюсь.

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

Десятки типов и методов будет. Обёртка на питоне такая жирная получится, что проще на самом питоне написать. Да и там нет ничего такого, чтобы могло сильно тормозить. Учитывая что сам xml будет парсится через тот же lxml, который и так на сишке.

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от eao197

Дело ж не в моде. Интерфейс/абстрактный класс + наследники, удобен тогда, когда заранее неизвестно, какие будут разновидности объектов, но известны базовые операции над ними. Adt, наоборот, когда число разновидностей известно (относительно стабильно), а вот операций над данными множество.

anonymous
()
Ответ на: комментарий от RazrFalcon

без фанатизма. :). в контексте python посмотри в сторону namedtuple.

maxim2
()
Ответ на: комментарий от RazrFalcon

Десятки типов и методов будет. Обёртка на питоне такая жирная получится

Обертка чего? Вот есть у нас гипотетическая функция:

def load_svg(fname: str) -> SVGShit

Понятно, что SVGShit будет корневым объектом чего-то сложного. У чего будут десятки типов - у SVGShit? Даже если так, всего-навсего десятки типов и методов - это не нагрузка, у Python приличный FFI. А если все эти десятки типов сужествуют только во время работы load_svg, вообще говорить не о чем.

что проще на самом питоне написать.

Если речь об rsvg - не проще.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Понятно, что SVGShit будет корневым объектом чего-то сложного.

Чего именно? Мы вроде путь парсим. Но если речь идёт про SVG в целом, то там десятки мелких объектов. Хз как устроен CPython, но если он всё в куче будет выделять - это же ппц что будет.

Если речь об rsvg - не проще.

librsvg? Ну как писать что-то сложнее 100 строк на питоне/скриптоте я вообще не представляю.

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от RazrFalcon

Но если речь идёт про SVG в целом, то там десятки мелких объектов. Хз как устроен CPython, но если он всё в куче будет выделять - это же ппц что будет.

Не будет. Откуда вообще эта боязнь кучи? Выделения в ней следует избегать разве что в глубоких циклах. А где объект лежит - вообще без разницы.

librsvg?

resvg. Твоя библиотека - я думал, речь о ней.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Откуда вообще эта боязнь кучи?

Дорого. Особенно в условиях FFI. Мораль в том, что можно просадить выигрыш от сишка на FFI. Но без бенчей не понять.

resvg. Твоя библиотека - я думал, речь о ней.

Она не при чём. Текущая задача - это просто развлечение.

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от RazrFalcon

Откуда вообще эта боязнь кучи?

Дорого. Особенно в условиях FFI.

Даже не могу придумать, на чем могу бы быть основан этот вывод.

Мораль в том, что можно просадить выигрыш от сишка на FFI.

Разве что если ходить в Си за каждым обращением к атрибуту, да и то я сомневаюсь.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Даже не могу придумать, на чем могу бы быть основан этот вывод.

malloc дорогой.

Разве что если ходить в Си за каждым обращением к атрибуту

Так об этом и речь.

RazrFalcon ★★★★★
() автор топика

Чуток оффтопика - как это будет выглядеть на D:

    alias Item = SumType!(int, string);
    Item[] items;
    
    items ~= Item(5);
    items ~= Item("text");
    
    foreach(item; items) {
        item.match!(
            (   int num) => writeln("number: ", num),
            (string str) => writeln("string: ", str),
        );
    }
онлайн

Хмм... Получилось кратко и понятно ;)

yetanother ★★
()
Ответ на: комментарий от RazrFalcon

Уточнение принято. Только стандартная либа:

    alias Item = Algebraic!(int, string);
    Item[] items;
    
    items ~= Item(5);
    items ~= Item("text");
    
    foreach(item; items)
    {
        item.visit!(
            (   int num) => writeln("number: ", num),
            (string str) => writeln("string: ", str),
        );
    }
онлайн

Но я не пользуюсь этими типами, в свое время подсел на TaggedAlgebraic (другая либа) и в коде юзаю его. Точнее один раз написал и забыл (но код в постоянном использовании). По ощущениям sumtype перспективная вещь и удобнее чем стандартная либа. sumtype умеет делать а-ля структурный паттернматчинг (не знаю насколько он сравним с растовым - в расте это все-таки в языке, а не в либе)

yetanother ★★
()
Ответ на: комментарий от Deleted

Как там с экосистемой сейчас?

Ну так как вопрос общий, то и ответ будет таким же - нормально там с инфраструктурой как по мне. Без лишней суеты все уверенно (хоть и не быстро) движется вперед. Что запомнил из последнего - по маленьку добавляют интеграцию со стандартной либой С++, добавили недавно std::array, std::string_view, например. Но я на линуксе сижу, на винде движений больше - улучшают юзер экпириенс, вроде как уже вижуал студию не нужно качать, сертификаты получили от мелкомягких чтобы антивирусы не ругались и пр. Конечно работать есть над чем, а так каждому нужно смотреть для себя, конечно.

yetanother ★★
()
Ответ на: комментарий от tailgunner

Вариант в match всё так же можно забыть, и компилятор ничего не скажет?

Так вроде же ругается компилятор?

alias Item = Algebraic!(int, string);
    Item[] items;
    
    items ~= Item(5);
    items ~= Item("text");
    
    foreach(item; items)
    {
        item.visit!(
            (   int num) => writeln("number: ", num),
            //(string str) => writeln("string: ", str),     <== Комментируем обработку строк
        );
    }
static assert срабатывает если не все кейсы предусмотрены
/dlang/dmd/linux/bin64/../../src/phobos/std/variant.d(2557): Error: static assert:  "overload for type 'string' hasn't been specified"

В sumtype и structural matching есть - т.е. это не просто свитч по типу. Про другие либы не скажу, не знаю.

yetanother ★★
()
Ответ на: комментарий от yetanother

Так вроде же ругается компилятор?

Да, всё правильно делает. Просто, когда я еще интересовался D, ветку можно было молча пропустить.

В sumtype и structural matching есть

Интересно, это их собственное изобретение или собственный термин.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Интересно, это их собственное изобретение или собственный термин.

Да вроде нет, есть в инете упоминания сего и в других языках: java и typescript

По мне так это форма утиной типизации. Но сейчас модно изобретать красивые термины. Вон хорошо известный метод градиентного спуска взяли обозвали метод обратного распространения ошибки и вот, уже другое впечатление - нейронные сети, все таки.

yetanother ★★
()
Ответ на: комментарий от tailgunner

Не помогло. Да и ошибки компилятора ппц:

/dlang/dmd/linux/bin64/../../src/phobos/std/variant.d(2569): Error: mismatched function return type inference of void and int
/dlang/dmd/linux/bin64/../../src/phobos/std/variant.d(2253): Error: template instance `std.variant.visitImpl!(true, VariantN!(16LU, int, string), function (ref int num) => num = 6, function (string str)
{
writeln("string: ", str);
return ;
}
)` error instantiating
onlineapp.d(13):        instantiated from here: visit!(VariantN!(16LU, int, string))
RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от RazrFalcon

vs

error[E0384]: cannot assign twice to immutable variable `n`
  --> src/main.rs:13:32
   |
13 |             Data::Number(n) => n = 6,
   |                          -     ^^^^^ cannot assign twice to immutable variable
   |                          |
   |                          first assignment to `n`
   |                          help: make this binding mutable: `mut n`

Привык я к хорошему.

RazrFalcon ★★★★★
() автор топика
Последнее исправление: RazrFalcon (всего исправлений: 1)
Ответ на: комментарий от yetanother

Там у structural matching другой смысл - «destructuring binding», в левой части всё равно указывается тип варианта (и, насколько я помню, так во всех языках с PM); а в D и в самом деле какая-то утиная типизация в compile time. Они использовали существующий термин в другом смысле

tailgunner ★★★★★
()
Ответ на: комментарий от RazrFalcon

~= - это push/append?

Да, но если точнее то это аналог `+=` - в D конкатенация обозначается не `+`, а `~` - довольно эффективно.

А модифицировать как? (int num) => num = 6, не работает.

Не нашел, `ref` действительно не помогает.

ошибки компилятора ппц

Ну это же библиотечное решение, поэтому компилятор ругается что в одном кейсе возвращается `void`, а в другом `int`, что правильно, но ошибка не становится очевидной. Хотя тут можно добавить диагностику с нужным сообщением, в D этого реально легко. В Расте же поддержка АТД на уровне языка, поэтому сообщение читабельнее.

yetanother ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.