Чтение чисел из stdin в массив
Допустим у нас есть массив структур,где экземпляр структуры описывает человека. Поля структуры - имя и возраст. Чтобы не читать данные этих полей из stdin в строку, так как это опснода и не хочется парсить потом строку в поисках чисел, читать я всё это буду в массивы u8. И тут возникает проблема - функция read читает из stdin код числа, а не само число. Можно ли это как-то изменить или преобразовать код числа в число?
use std::io::{self, Write, Read};
use std::str;
static AMOUNT: usize = 3;
//создаём структуру
struct Person {
name: String,
age: u8
}
fn main() {
let mut people: Vec<Person> = Vec::with_capacity(AMOUNT); //вектор структур
let mut raw_name: [u8; 30] = [0; 30]; // буффер, куда мы будем читать имя из потока
let mut age: [u8; 2] = [0; 2]; //буффер, куда мы будем читать возраст из потока
let mut name: String = String::new(); //2-ой байт, чтобы ловить символ новой строки
for _ in 0..AMOUNT {
print!("Имя: ");
io::stdout().flush().unwrap();
io::stdin().read(&mut raw_name).unwrap();
print!("Возраст: ");
io::stdout().flush().unwrap();
io::stdin().read(&mut age).unwrap();
name = str::from_utf8(&mut raw_name)
.unwrap()
.trim_matches(|c| c == ' ' || c == '\n')
.to_string();
let tmp: Person = Person {name: name.clone(), age: age[0]};
people.push(tmp);
name.clear();
}
for index in 0..AMOUNT {
println!("{}", people[index].name);
println!("{}", people[index].age);
}
}
Будет выводить код числа
println!("{}", people[index].age);
Можно в этом легко убедиться: так выводит нужное нам число.
println!("{}", people[index].age as char);
и еще trim_matches почему-то не удаляет символ новой строки
Ответы (1 шт):
Можно ли это как-то изменить или преобразовать код числа в число?
Да, нужно из каждой цифры отнять код числа 0.
age: age[0] - b'0'
и еще trim_matches почему-то не удаляет символ новой строки
Вы вызываете функцию str::from_utf8 для всего буфера [u8; 30]. Внутри эта функция проверяет только корректность последовательности для utf8, а потом возвращает ссылку на этот же кусок памяти в виде строки.
Это означает, что при вводе имени Ваня в функцию передаётся массив содержащий Ваня\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 и trim просто не срабатывает на такой строке.
Для корректной обработки вы можете получить от функции read количество считанных байт и передать только нужный кусок.
let name_len = io::stdin().read(&mut raw_name).unwrap();
name = str::from_utf8(&raw_name[0..name_len]).unwrap().trim().to_string();
Ещё для избежания проблем с синхронизацией я рекомендую запросить stdin и stdout до цикла. А для лучшей обработки ошибок в main можно возвращать Result<(), io::Error>
fn main() -> Result<(), io::Error> {
let mut people: Vec<Person> = Vec::with_capacity(AMOUNT); //вектор структур
let mut raw_name: [u8; 30] = [0; 30]; // буффер, куда мы будем читать имя из потока
let mut age: [u8; 2] = [0; 2]; //буффер, куда мы будем читать возраст из потока
let mut name: String = String::new(); //2-ой байт, чтобы ловить символ новой строки
let mut stdout = io::stdout();
let mut stdin = io::stdin();
for _ in 0..AMOUNT {
print!("Имя: ");
stdout.flush()?;
let name_len = stdin.read(&mut raw_name)?;
print!("Возраст: ");
stdout.flush()?;
stdin.read(&mut age)?;
name = str::from_utf8(&raw_name[0..name_len]).unwrap().trim().to_string();
let tmp: Person = Person {
name: name.clone(),
age: age[0] - b'0',
};
people.push(tmp);
name.clear();
}
for index in 0..AMOUNT {
println!("{}", people[index].name);
println!("{}", people[index].age);
}
Ok(())
}
Но в целом я не вижу особого смысла в том чтобы использовать u8 буферы в данному случае. Это только всё усложняет, да и возраст у вас даже двузначный не запишется.
use std::io::{self, Write};
const AMOUNT: usize = 3;
//создаём структуру
#[derive(Default)]
struct Person {
name: String,
age: u8,
}
fn main() -> Result<(), io::Error> {
let mut people: Vec<Person> = Vec::with_capacity(AMOUNT); //вектор структур
let mut buf = String::new();
let mut stdout = io::stdout();
let stdin = io::stdin();
for _ in 0..AMOUNT {
let mut person = Person::default();
print!("Имя: ");
stdout.flush()?;
stdin.read_line(&mut buf)?;
person.name = buf.trim().to_owned();
buf.clear();
print!("Возраст: ");
stdout.flush()?;
stdin.read_line(&mut buf)?;
person.age = buf.trim().parse().unwrap_or_default();
buf.clear();
people.push(person);
}
for p in &people {
println!("{} {}", p.name, p.age);
}
Ok(())
}