Как идиоматически конвертировать между u32 и usize?
Этот код работает и печатает "б":
fn main() {
let s = "abc";
let ch = s.chars().nth(1).unwrap();
println!("{}", ch);
}
С другой стороны, этот код приводит к ошибке несоответствия типов.
fn main() {
let s = "abc";
let n: u32 = 1;
let ch = s.chars().nth(n).unwrap();
println!("{}", ch);
}
error[E0308]: mismatched types
--> src/main.rs:5:28
|
5 | let ch = s.chars().nth(n).unwrap();
| ^ expected usize, found u32
По какой-то внешней причине я должен использовать тип u32
для переменной n
. Как я могу преобразовать u32
в usize
и использовать его в nth()
?
Ответы
Ответ 1
Оператор as
работает для всех типов номеров:
let ch = s.chars().nth(n as usize).unwrap();
Rust заставляет вас вводить целые числа, чтобы убедиться, что вы знаете о подписанности или переполнениях.
Целочисленные константы могут иметь суффикс типа:
let n = 1u32;
Однако обратите внимание, что отрицательные константы, такие как -1i32
, являются внутренними -
1i32
.
Целочисленные переменные, объявленные без явной спецификации типа, отображаются как {integer}
и будут правильно выведены из одного из вызовов метода.
Ответ 2
Самое осторожное, что вы можете сделать, это использовать TryFrom
и паниковать, когда значение не может поместиться в usize
:
use std::convert::TryFrom;
fn main() {
let s = "abc";
let n: u32 = 1;
let n_us = usize::try_from(n).unwrap();
let ch = s.chars().nth(n_us).unwrap();
println!("{}", ch);
}
При слепом использовании as
ваш код будет таинственным образом не работать при запуске на платформе, где usize
меньше 32-битного. Например, некоторые микроконтроллеры используют 16-битные целые числа в качестве собственного размера:
fn main() {
let n: u32 = 0x1_FF_FF;
// Pretend that 'usize' is 16-bit
let n_us: u16 = n as u16;
println!("{}, {}", n, n_us); // 131071, 65535
}
Ответ 3
Теперь у нас совсем другой ответ, когда мы пытаемся скомпилировать ваш код, заменив число 1
на переменную типа i32
:
error[E0308]: mismatched types
--> src/main.rs:5:28
|
5 | let ch = s.chars().nth(n).unwrap();
| ^ expected usize, found i32
help: you can convert an 'i32' to 'usize' and panic if the converted value wouldn't fit
|
5 | let ch = s.chars().nth(n.try_into().unwrap()).unwrap();
|
Это означает, что теперь компилятор рекомендует использовать n.try_into().unwrap()
, который использует черту TryInto
, которая в свою очередь опирается на TryFrom
и возвращает Result<T, T::Error>
. Вот почему нам нужно извлечь результат с помощью .unwrap()
TryInto
документация