【问题标题】:Is it possible to overload a function with different numbers of arguments (using traits)是否可以重载具有不同数量参数的函数(使用特征)
【发布时间】:2017-02-14 21:03:19
【问题描述】:

我正在尝试使用一个带有一个和两个参数的new 构造函数,但我似乎无法弄清楚如何做到这一点。目前这是否可能?

我现在得到的错误是多个适用项目在范围内 (playground)

trait __Constructor1<T> {
    fn new(T) -> Self;
}
trait __Constructor2<T, U> {
    fn new(T, U) -> Self;
}

enum MixedInts {
    SmallInt(i32),
    TwoSmallInts(i32, i32),
}

impl __Constructor1<i32> for MixedInts {
    fn new(__0: i32) -> MixedInts {
        MixedInts::SmallInt(__0)
    }
}
impl __Constructor2<i32, i32> for MixedInts {
    fn new(__0: i32, __1: i32) -> MixedInts {
        MixedInts::TwoSmallInts(__0, __1)
    }
}

fn main() {
    let x = MixedInts::new(2i32);
    let y = MixedInts::new(2i32, 2i32);
}

【问题讨论】:

  • 我知道您只是尝试创建一个小示例.. 但是这里的 trait 用法非常无用。稍微改变一下你的例子,我have seen this technique used in a few codebases
  • @SimonWhitehead 我不确定您的代码应该实现什么。它根本不接受不同数量的参数,并且由于某种原因它创建了第二种类型而不是枚举。
  • 目的是演示使用枚举作为“重载”函数的一种方式。您可以使用枚举变体将不同数量的参数传递给函数。因此,它通过使用枚举作为“重载”机制来翻转您的示例 - 我只是使用结构作为示例来强调我示例中的枚举是主要部分。

标签: rust


【解决方案1】:

Rust 不支持重载的函数/方法。作为一种解决方法,您可以使用元组在单个参数中接收多个值。然后,您可以定义一个特征并为该单个参数的可接受类型实现它,该函数将简单地委托给该特征的实现。

enum MixedInts {
    SmallInt(i32),
    TwoSmallInts(i32, i32),
}

trait IntoMixedInts {
    fn into(self) -> MixedInts;
}

impl MixedInts {
    fn new<A>(args: A) -> MixedInts
        where A: IntoMixedInts
    {
        args.into()
    }
}

impl IntoMixedInts for i32 {
    fn into(self) -> MixedInts {
        MixedInts::SmallInt(self)
    }
}

impl IntoMixedInts for (i32, i32) {
    fn into(self) -> MixedInts {
        MixedInts::TwoSmallInts(self.0, self.1)
    }
}

fn main() {
    let x = MixedInts::new(2i32);
    let y = MixedInts::new((2i32, 2i32));
}

注意:在此示例中,您可以使用标准的 FromInto 特征,而不是定义您自己的特征。但是,由于一致性规则(确保特定类型的特定特征只能存在一个实现的规则),它可能不适用于其他特征。

enum MixedInts {
    SmallInt(i32),
    TwoSmallInts(i32, i32),
}

impl MixedInts {
    fn new<A>(args: A) -> MixedInts
        where A: Into<MixedInts>
    {
        args.into()
    }
}

impl From<i32> for MixedInts {
    fn from(a: i32) -> MixedInts {
        MixedInts::SmallInt(a)
    }
}

impl From<(i32, i32)> for MixedInts {
    fn from((a, b): (i32, i32)) -> MixedInts {
        MixedInts::TwoSmallInts(a, b)
    }
}

fn main() {
    let x = MixedInts::new(2i32);
    let y = MixedInts::new((2i32, 2i32));
}

【讨论】:

  • 注意:Rust 确实支持通过特征重载;它似乎不如使用 Into/From 实用,但它是受支持的。
【解决方案2】:

在技术上是可能的,但不是以实用的方式。您需要使用 Rust 的 Universal Function Call Syntax 来消除对 new 的调用的歧义。

fn main() {
    let x = <MixedInts as __Constructor1<i32>>::new(2i32);
    let y = <MixedInts as __Constructor2<i32, i32>>::new(2i32, 2i32);
}

Iron 框架有一个有趣的Modifier pattern,我认为可以实现你想要的。虽然它非常聪明,但最终会让用户感到困惑。

【讨论】:

  • 链接上的404
【解决方案3】:

我建议使用标准库中的 From/Into 特征。

#[derive(PartialEq, Eq, Debug)]
enum MixedInts {
    SmallInt(i32),
    TwoSmallInts(i32, i32),
}

impl From<i32> for MixedInts {
    fn from(n: i32) -> Self {
        MixedInts::SmallInt(n)
    }
}

impl From<(i32, i32)> for MixedInts {
    fn from((a, b): (i32, i32)) -> Self {
        MixedInts::TwoSmallInts(a, b)
    }
}

fn main() {
    let x: MixedInts = 2_i32.into();
    assert_eq!(x, MixedInts::SmallInt(2));

    let y: MixedInts = (2_i32, 2_i32).into();
    assert_eq!(y, MixedInts::TwoSmallInts(2, 2));
}

example on Rust Playground

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-23
  • 2014-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-11
  • 2014-06-29
相关资源
最近更新 更多