首页 > 解决方案 > 如何在 Rust 中命名关联函数的类型?

问题描述

我正在尝试编写对操作通用的代码,但也具有常用功能的便利功能,例如我想为所有类型定义的加法T: Add

如果我定义独立函数,这很好用,因为我可以impl Trait在返回值中使用来隐藏不透明类型。

但是,如果我想在 trait 中定义这个函数,我不得不将类型命名为<T as Add>::add. 我怎样才能做到这一点?

use std::ops::Add;

struct Operation<T, F>
where
    F: Fn(T, T) -> T,
{
    arg: T,
    f: F,
}

fn addition<T>(arg: T) -> Operation<T, impl Fn(T, T) -> T>
where
    T: Add<Output = T>,
{
    Operation { arg, f: T::add }
}

trait Addable<T>
where
    T: Add<Output = T>,
{
    fn addition(self) -> Operation<T, impl Fn(T, T) -> T>;
    //fn addition(self) -> Operation<T, ???>;
}

错误:

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
  --> src/main.rs:22:39
   |
22 |     fn addition(self) -> Operation<T, impl Fn(T, T) -> T>;
   |                                       ^^^^^^^^^^^^^^^^^^

标签: functiongenericsrustclosurestraits

解决方案


impl Traittrait 方法的返回位置不允许的原因是因为该方法可以有多个实现,而impl Trait只有在函数或方法的单个实现时才有效。

一种选择是使用盒装特征对象闭包:

trait Addable<T>
where
    T: Add<Output = T>,
{
    fn addition(self) -> Operation<T, Box<dyn Fn(T, T) -> T>>;
}

但是,由于闭包似乎不太可能需要从其环境中捕获变量,因此您可以改用普通函数指针。这为您节省了不必要的堆分配。这是一个i32在 trait 方法返回类型中使用普通函数指针的简单示例:

trait Addable<T>
where
    T: Add<Output = T>,
{
    fn addition(self) -> Operation<T, fn(T, T) -> T>;
}

struct SomeType {
    arg: i32,
}

impl Addable<i32> for SomeType {
    fn addition(self) -> Operation<i32, fn(i32, i32) -> i32> {
        Operation {
            arg: self.arg,
            f: i32::add,
        }
    }
}

这是一个在 trait 方法返回类型中使用普通函数指针的通用示例:

trait Addable<T>
where
    T: Add<Output = T>,
{
    fn addition(self) -> Operation<T, fn(T, T) -> T>;
}

struct SomeType<T> {
    arg: T,
}

impl<T> Addable<T> for SomeType<T>
    where T: Add + Add<Output = T>
{
    fn addition(self) -> Operation<T, fn(T, T) -> T> {
        Operation {
            arg: self.arg,
            f: T::add,
        }
    }
}

推荐阅读