#rust
#Ржавчина
Вопрос:
В чем разница между One::one()
и просто числом 1
? Есть ли какая-либо разница?
Ответ №1:
One::one()
предназначен для использования в общем коде, где мы не знаем, каков точный тип числового значения.
Это может быть 1_i32
, 1.0
, 1_u8
… в зависимости от точного типа One
, к которому привязан признак.
Благодаря полезным комментариям ниже, вот минимальный пример, чтобы попытаться лучше проиллюстрировать (хотя уже поздно).
Попытка инициализировать некоторые переменные с 1
помощью works, если они рассматриваются как целые числа ( a
и c
здесь ). С другой стороны, это не работает для реального ( b
здесь); 1.0
должен использоваться вместо этого.
Когда дело доходит до нашего собственного непримитивного типа ( Thing
здесь ), One
признак помогает предоставить значение, рассматриваемое как 1
(обратите внимание, что Mul
признак также должен быть реализован для этого типа).
One
Признак становится действительно полезным в универсальной функции, в которой точный тип еще не известен, когда нам нужно 1
значение (как mul_one()
здесь ).
use num_traits::One;
use std::ops::Mul;
#[derive(Debug)]
struct Thing {
member: String,
}
// Mul<Self, Output = Self> is required for One
impl Mul for Thing {
type Output = Self;
fn mul(
self,
rhs: Self,
) -> Self {
Self {
member: self.member "×" amp;rhs.member,
}
}
}
impl One for Thing {
fn one() -> Self {
Self {
member: "one".to_owned(),
}
}
}
fn mul_one<T: One>(arg: T) -> T {
// arg * 1 // error: expected type parameter `T`, found integer
arg * T::one()
}
fn main() {
let a: i32 = 1;
// let b: f64 = 1; // error: expected `f64`, found integer
let b: f64 = 1.0;
let c: u8 = 1;
let d = Thing::one();
println!("{:?} {:?} {:?} {:?}", a, b, c, d);
let e = mul_one(a);
let f = mul_one(b);
let g = mul_one(c);
let h = mul_one(d);
println!("{:?} {:?} {:?} {:?}", e, f, g, h);
}
/*
1 1.0 1 Thing { member: "one" }
1 1.0 1 Thing { member: "one×one" }
*/
Комментарии:
1. В дополнение к этому ответу: литерал
1
будет работать для любого из упомянутых типов, но только если конкретный тип известен на сайте использования. Однако, поскольку нет признака, связанного с литералами, невозможно использовать1
для универсального типа, независимо от того, какие границы признаков вы установили. То есть вы не можете написать ничегоfn foo<T>() -> T where T: ??? { 1 }
, что будет компилироваться, независимо от того, что вы???
заменяете.2. Кроме того,
One
может быть реализовано для непримитивных типов, которые имеют «единство» в отношении них. Например, комплексные числа или объекты из линейной алгебры.