【问题标题】:simple rust generic/template add function简单的 rust 通用/模板添加功能
【发布时间】:2020-09-04 21:16:28
【问题描述】:

所以我只是在学习 rust - 我已经设置了工具并使其在结构上正常工作,交叉编译,链接库等等......但是现在我正在探索我现在想编写的一些简单函数之后的语言一些模板(我有 C++ 背景)。所以在 c++ 谈话中我想这样做:

C++

template<typename A, typename B>
auto add(A a, B b)
{
    return a + b;
}

int main() {
    std::cout << "add int int:    " << add(1, 2) << std::endl;
    std::cout << "add int double: " << add(1, 2.3f) << std::endl;
    std::cout << "add int float:  " << add(1, 2.3) << std::endl;
    std::cout << "add char int:   " << add('g', 2.3) << std::endl;
    std::cout << "add str str:    " << add(std::string("bob"), std::string("fred")) << std::endl;
}

输出:

add int int:    3
add int double: 3.3
add int float:  3.3
add char int:   105.3
add str str:    bobfred

这增加了“事物”。如果您尝试使用正确的操作数添加两个未实现正确的 + 运算符的东西,您将收到编译错误(例如添加字符串和 int) - 非常简单。

现在要生锈了(我完全没有掌握它的窍门。

普通添加功能

pub fn add(a: u64, b: u64) -> u64 {
    return a + b;
}

到目前为止还可以。

尝试 1 对此进行模板化 我通过听取错误并使用建议的更改来实现此实现(使用std::ops::Add&lt;Output = T&gt; 我有点理解它,但我真的不知道为什么我必须指定它。

pub fn add<T: std::ops::Add<Output = T>>(a: T, b: T) -> T
{
    return a + b;
}


println!("add int int:   {}", add(1, 2));    // ok
println!("add int float: {}", add(1, 2.3));  // fails to compile

这是意料之中的,因为我只告诉它一种类型....所以现在尝试两种类型 A,B - 但这是我迷路的地方:

pub fn add<A: std::ops::Add<Output = A>, B: std::ops::Add>(a: A, b: B) -> A
{
    return a + b;
}

我得到的错误是:

error[E0308]: mismatched types
  --> utils/src/lib.rs:19:16
   |
17 | pub fn add<A: std::ops::Add<Output = A>, B: std::ops::Add>(a: A, b: B) -> A
   |            - expected type parameter     - found type parameter
18 | {
19 |     return a + b;
   |                ^ expected type parameter `A`, found type parameter `B`
   |
   = note: expected type parameter `A`
              found type parameter `B`
   = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.

所以现在我完全迷路了。首先,我似乎必须指定一个返回类型——但我希望为我推断出它。我怎么做?其余的错误可能都是由于返回类型为A - 但我似乎必须指定一些东西......这里的任何帮助都会很棒! - 如果可能的话,我想归档与上面的 c++ 模板相同的基本功能

【问题讨论】:

    标签: c++ templates generics rust


    【解决方案1】:

    首先,你最好先参考std::ops::Add的文档。您已经设置了一个type Output,但您也可以设置一个模板参数Rhs。所以你可以试试:

    pub fn add_to_rhs<A, B>(a: A, b: B) -> B
      where A: std::ops::Add<B, Output = B>
    {
        return a + b;
    }
    

    您声明 LHS 值应该与 RHS 值相加,最后产生一种 RHS 值。但这仍然无法按您的预期工作

    println!("add int float: {}", add_to_rhs(1, 2.3)); 
    // fails to compile, no implementation for `{integer} + {float}`
    

    这是合理的,因为弱类型不适合 Rust,因为它容易出现逻辑错误。什么是可能的解决方法?实际上类似于您在非泛型程序中所做的 - 您将显式转换其中一个值:

    pub fn add_to_rhs<A, B>(a: A, b: B) -> B
    where A: Into<B>, B: std::ops::Add<Output = B>
    {
        return a.into() + b;
    }
    

    这并没有达到与 C++ SFINAE 相同的灵活性(记住,没有弱类型),因为要添加任何值,您需要创建一个函数的两个版本;我展示了一个变体,其中 LHS 值被转换并添加到 RHS 类型,但您也需要其他方式。

    由于我们在 Rust 中没有重载,这变得更加不方便,您必须调用不同的函数并牢记这一点。

    编辑:我玩了一点,并设法为不同的类型混合使用一个函数,但使用它强制您每次都指定返回类型

    struct Adder<T>(std::marker::PhantomData<T>);
    impl<T> Adder<T> {
        fn add<A, B>(a: A, b: B) -> T
          where T: std::ops::Add<Output = T>, A: Into<T>, B: Into<T> {
            return a.into() + b.into();
        }
    }
    
    
    println!("add int int:   {}", Adder::<i32>::add(1, 2));
    println!("add int float: {}", Adder::<f64>::add(1, 2.3)); 
    println!("add float int: {}", Adder::<f64>::add(2.3, 1));
    

    结构的目的是将add的模板参数(可以完全推导)与生成的模板参数(您需要指定,否则返回类型不明确)分开

    【讨论】:

    • 这是一个很好的解释 - 有点粗略的语法,但从你所说的来看,这是 因为 rust 会强制使用强类型函数,所以缺点就是它更少灵活 - 但好处是您可以获得各种安全优势(这是我的额外推论) - 这确实有助于了解 为什么 我不能做与 c++ 相同的事情以及为什么它更冗长。 ……这样对吗?
    • @code_fodder 检查我的编辑。是的,Rust 的首要任务是防止在编译时发生错误。 C++ SFINAE(如果你愿意,也可以是鸭子类型)非常难以调试,尤其是如果你在实现事物时打破了一些合理的规则,例如int + float 的重载以充当 int * float
    • 好的,这实际上很有意义(好吧,我需要阅读那里的语法 - 远远超出我的理解!) - 与c ++ ..我习惯于让编译器为我做很多计算 - 但正如你所说,当你弄错时会很痛苦! - 谢谢
    猜你喜欢
    • 1970-01-01
    • 2016-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-03
    • 2014-05-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多