Comments 15
Очень странный язык. Мне аж стало интересно попробовать на современном языке такую штуку реализовать.
… перепрочитал задание. Целых? Любых? Даже если число — это что-то в районе 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, но данные могут быть гораздо сложнее а стоимость их валидации — даже в разы выше стоимости обработки (напомню — вам "сверху" гарантируют правильные данные).
Валидация выполняется в рантайме, а гарантии (вы же говорите про гарантии) нам предоставляет система типизации. То есть если у меня функция 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?).
Клонированные переменные