Pull to refresh

Comments 15

Имхо, не самый удачный пример. Здесь по сути весь алгоритм базируется на не очевидной побочной особенности работы языка, поэтому с понятностью и читабельностью у него очень сильно так себе, особенно для тех, кто с таким колдунством не знаком. На любом другом языке, где есть стек/массив/список с функциями push и pop, это будет в разы понятнее и не хуже по ресурсам.
Тот же сишный std::vector лучше по ресурсам, потому что не потребует аллокации памяти на каждый push, а будет аллоцировать блоками и хранить данные максимально плотно — подряд, без оверхеда на указатели и разметку кучи.
Согласен, но даже std::vector в стандартной реализации производительнее односвязного списка в задаче «положи много, потом вытащи в обратном порядке»

Очень странный язык. Мне аж стало интересно попробовать на современном языке такую штуку реализовать.


… перепрочитал задание. Целых? Любых? Даже если число — это что-то в районе 2**100000000000? Или всё-таки машинных чисел? Объём работы от этого различается в разы. Вот для i64 (вместе с рудиментарной обработкой ошибок, типа "не число" на входе или "число слишком большое":


use std::io;
use std::io::prelude::*;
fn main() {
    let stdin = std::io::stdin();
    let nums = stdin.lock().lines()
        .map(|line|{line.unwrap().trim().parse::<i64>().unwrap()})
        .filter(|x|{ x % 2 == 1})
        .fold(Vec::new(), |mut acc, x|{acc.push(x);acc});
    for num in nums.iter().rev(){
       println!("{}", num);
    }
}

В целом пример хороший, потому что заставляет очень много языковых конструкций трогать.

Если речь о целых в десятичной записи (и вообще любой где база кратна 2), то разрядность не имеет значения — ими можно оперировать как строками, а чётность определять по последней цифре.

Интересная идея, да. Но это при условии, что мы используем подход garbage in garbage out, т.е. 1980ые-90ые. Ваш алгоритм для строки not-a-number-3 выдаст его как odd, вместо того, чтобы свалиться.

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

"условия задачи гарантируют" — это и есть garbage in/garbage out.

Нет. Потому что не может быть garbage in, значит не может и out. По определению. Может там на входе стоит железный валидатор, или стадо обезьян всё проверяет лапками — это неважно, на входе гарантированы только целые числа.


Если вы будете писать библиотеку или функцию/приложение для неясно кого — да, валидация может быть нужна (но это не точно), если вы работаете с данными полученными от неизвестно кого неизвестно откуда — нужна безусловно, но во всех остальных случаях — нужно исходить из условий конкретной задачи. Всё же иногда людям (и данным) можно и нужно верить.

И каким образом обеспечивается "не может быть garbage in"? Доверием к кишечной трубке с мозгом сверху?


В коде я могу сказать "тут мне не могут передать не число". Я это пишу так:


fn foo(x: i64) -> i64

А в stdin, как известно, пишется фигня. Enter'ы, лишние пробелы, или вообще "опечатался". Это garbage in. А программа в ответ делает garbage out.


Этим принципом руководствовались несколько поколений программистов, пока не оказалось, что это нарастающая катастрофа.

Допустим что валидация занимает существенное время (даже если речь про int64 — да, существенное), и у вас функция которая должна обрабатывать данные, но вызывается она уже после валидации на верхнем уровне, который обязуется предоставлять только правильные данные и берет на себя все риски с этим связанные (для простоты — представте grep -E '^[0-9]+$' перед вашим stdin).


Вы правда при таком раскладе обвешаетесь валидацией? Ладно это парсинг int64, но данные могут быть гораздо сложнее а стоимость их валидации — даже в разы выше стоимости обработки (напомню — вам "сверху" гарантируют правильные данные).

UFO just landed and posted this here

Валидация выполняется в рантайме, а гарантии (вы же говорите про гарантии) нам предоставляет система типизации. То есть если у меня функция foo принимает i64, то вызывающий гарантирует, что внутри параметра будет i64.


Теперь посмотрим на функцию, которая работает с stdin. Что нам гарантирует stdin? В целом, что мы можем read, close, и (может быть) seek вперёд. А что нам read гарантирует? Блокирующее чтение bytes. Не i64, не str, даже, а чистой воды bytes, которые могут быть и бинарным блобом, и поломанным юникодом.


Ведь в исходом задании, обратите внимание, все просто подразумевали "ascii, десятичную систему кодирования, одно число на строку". Но в задании этого нет.


А ведь bytestream можно, например, интерпретировать как поток чисел [0-255], или i8, если хотите, либо как i32, или как i128.


И это всё human ambiguity, которые вырастают из "два мешка с кишками, может быть, сумели договориться". А может, и нет. И тогда garbage in/garbage out.


Правильный подход — входные данные валидируются, если нет внешней, консистентной системы, гарантирующей машиночитаемый контракт.


ТЗ в посте — не машиночитаемый контракт (ascii или protobuf в stdin, а может, вообще json streams?).

UFO just landed and posted this here
Sign up to leave a comment.

Articles