В чем разница между One::one() и 1

#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 может быть реализовано для непримитивных типов, которые имеют «единство» в отношении них. Например, комплексные числа или объекты из линейной алгебры.