【问题标题】:Rust's alternative for C++ ADL overloaded functions?Rust 替代 C++ ADL 重载函数?
【发布时间】:2020-12-06 12:46:10
【问题描述】:

有一个提供通用函数和一些实现的库:

#include <iostream>

namespace lib {
  struct Impl1 {};
  struct Impl2 {};

  void process(Impl1) { std::cout << 1; }
  void process(Impl2) { std::cout << 2; }

  template<typename T> void generalize(T t) { process(t); }
}

我想通过外部代码扩展它。以下是 C++ 允许这样做的方式:

#include <lib.h> // the previous snippet

namespace client {
  struct Impl3 {};

  void process(Impl3) { std::cout << 3; }
}

int main() { // test
  lib::generalize(client::Impl3{}); // it couts 3
}

注意:lib 的代码对client 的代码一无所知,并且仍然不执行动态调度。如何在我的 Rust 代码中实现相同的目标? (如果我不能,是否有类似的计划?)

【问题讨论】:

  • 顺便说一句,我可以用 C# 或 Java 等语言以某种方式做到这一点吗?
  • 这是一个相当具有误导性的示例(也就是说,它会让您远离解决方案)。您应该始终尝试在标准库的基本功能中找到示例,因为您很可能在其他语言的标准库中找到类似的功能。考虑具有用户定义的operator&lt; 的对象容器的std::sort。就像在您的人工示例中一样,std::sort 对您的类型一无所知,也不执行动态调度,但完全能够调用您的 operator&lt;。 Rust 如何处理这个问题?

标签: rust overloading generic-programming argument-dependent-lookup open-closed-principle


【解决方案1】:

当然,这正是traits 的用途:

pub mod lib {
    pub trait Impl {
        fn process(&self);
    }

    pub struct Impl1 {}
    pub struct Impl2 {}

    impl Impl for Impl1 {
        fn process(&self) {
            println!("1");
        }
    }

    impl Impl for Impl2 {
        fn process(&self) {
            println!("2");
        }
    }

    pub fn generalize<T: Impl>(t: T) {
        t.process();
    }
}

mod client {
    pub struct Impl3 {}

    impl super::lib::Impl for Impl3 {
        fn process(&self) {
            println!("3");
        }
    }
}

fn main() {
    lib::generalize(client::Impl3 {});
}

Playground 上查看。

【讨论】:

    【解决方案2】:

    Rust 更严格,可能需要lib 才能玩得好。它可以通过定义一个 trait 来定义支持 process 的东西来做到这一点:

    trait Processable {
      fn process(self);
    }
    
    struct Impl1 {}
    impl Processable for Impl1 {
      fn process(self) {/*TODO*/}
    }
    
    fn generalize<T: Processable>(t: T) { t.process(); }
    

    那么,Processable 可以被“外人”使用来通知系统Impl3 满足所需的接口:

    struct Impl3 {}
    impl Processable for Impl3 {
      fn process(self) {/*TODO*/}
    }
    

    那么generalize也可以调用Impl3

    【讨论】:

      猜你喜欢
      • 2019-06-21
      • 2023-04-08
      • 2012-10-13
      • 2012-10-31
      • 1970-01-01
      • 1970-01-01
      • 2014-06-18
      • 2011-05-22
      • 1970-01-01
      相关资源
      最近更新 更多