当前位置: 首页 > 知识库问答 >
问题:

如何为类型引用上的操作指定泛型特征?

茹高义
2023-03-14

我正在尝试创建一个对通用数字类型的特征抽象。指定我希望特征需要T(即T:Add

但是,当我尝试为

简化示例

use std::ops::Add;

trait Numeric where
    Self: Sized,
    // T + T
    Self: Add<Output = Self>,
    // T + &T
    Self: for<'a> Add<&'a Self, Output = Self>,
    // &T + T
    // should specify &T + T on this trait but instead causes compile
    // errors everywhere I try to use Numeric claiming no implementation
    // for &T + T
//  for<'a> &'a Self: Add<Self, Output = Self>,
    // &T + &T
    // should specify &T + &T on this trait but instead causes compile
    // errors everywhere I try to use Numeric claiming no implementation
    // for &T + &T
//  for<'a, 'b> &'a Self: Add<&'b Self, Output = Self>,
{}

impl <T> Numeric for T where
    // T + T
    T: Add<Output = Self>
    + Sized,
    // T + &T
    for<'a> T: Add<&'a T, Output = T>,
    // &T + T
    for<'a> &'a T: Add<T, Output = T>,
    // &T + &T
    for<'a, 'b> &'a T: Add<&'b T, Output = T>,
{}

// works
fn generic_add_0<T: Numeric>(a: T, b: T) -> T {
    a + b
}

// works
fn generic_add_1<T: Numeric>(a: T, b: &T) -> T {
    a + b
}

// doesn't infer &T + T from the trait?
fn generic_add_2<T: Numeric>(a: &T, b: T) -> T {
    a + b
}

// doesn't infer &T + &T from the trait?
fn generic_add_3<T: Numeric>(a: &T, b: &T) -> T {
    a + b
}

// works
fn generic_add_4<T: Numeric>(a: &T, b: &T) -> T
// I want to not have to specify this every time I use Numeric,
// I want Numeric to imply this constraint for me
where for<'a, 'b> &'a T: Add<&'b T, Output = T> {
    a + b
}

fn main() {
    generic_add_0(1.0, 2.0);
    generic_add_1(1.0, &2.0);
    generic_add_2(&1.0, 2.0);
    generic_add_3(&1.0, &2.0);
    generic_add_4(&1.0, &2.0);
}

共有1个答案

翟永春
2023-03-14

我想我已经设法回答了我自己的问题,因为我盯着num特性是如何做到的,并且跟踪和错误了很长一段时间。

我最初示例的这个修改版本创建了两个额外的特性,让您能够非常接近原始目标。尽管您仍然需要where子句,但当您为其他操作添加更多约束时,它的大小不会增加。

use std::ops::Add;

/**
 * Trait defining what a numeric type is, in this case just something
 * that can be added to a right hand side and yield itself as output
 */
trait NumericByValue<Rhs = Self, Output = Self>: Sized + Add<Rhs, Output = Output> {}

/**
 * All types implemeting the by value operations are NumericByValue
 */
impl <T, Rhs, Output> NumericByValue<Rhs, Output> for T where
    T: Add<Rhs, Output = Output> {}

/**
 * The trait to define &T op T and &T op &T versions for NumericByValue
 * based off the MIT/Apache 2.0 licensed code from num-traits 0.2.10
 * http://opensource.org/licenses/MIT
 * https://docs.rs/num-traits/0.2.10/src/num_traits/lib.rs.html#112
 *
 * The trick is that all types implementing this trait will be references,
 * so the first constraint expresses some &T which can be operated on with
 * some right hand side type T to yield a value of type T.
 *
 * In a similar way the second constraint expresses &T op &T -> T operations
 */
trait NumericRef<T>:
    // &T op T -> T
    NumericByValue<T, T>
    // &T op &T -> T
    + for<'a> NumericByValue<&'a T, T> {}

/**
 * All types implementing the operations from NumericByValue by reference,
 * are NumericRef<T>, ie a type like &u8 is NumericRef<u8>.
 */
impl <RefT, T> NumericRef<T> for RefT where
    RefT: NumericByValue<T, T>
    + for<'a> NumericByValue<&'a T, T> {}

/**
 * A trait extending the constraints in NumericByValue to
 * types which also support the operations with a right hand side type
 * by reference.
 *
 * When used together with NumericRef this can express all 4 by value
 * and by reference combinations for the operations using the
 * following
 *
 * ```ignore
 *  fn function_name<T: Numeric>()
 *  where for<'a> &'a T: NumericRef<T> {
 * ```
 */
trait Numeric: NumericByValue + for<'a> NumericByValue<&'a Self> {}

/**
 * All types implemeting the operations in NumericByValue with a right hand
 * side type by reference are Numeric.
 */
impl <T> Numeric for T where T: NumericByValue + for<'a> NumericByValue<&'a T> {}

fn generic_add_0<T: Numeric>(a: T, b: T) -> T
where for<'a> &'a T: NumericRef<T> {
    a + b
}

fn generic_add_1<T: Numeric>(a: T, b: &T) -> T
where for<'a> &'a T: NumericRef<T> {
    a + b
}

fn generic_add_2<T: Numeric>(a: &T, b: T) -> T
where for<'a> &'a T: NumericRef<T> {
    a + b
}

fn generic_add_3<T: Numeric>(a: &T, b: &T) -> T
where for<'a> &'a T: NumericRef<T> {
    a + b
}

fn main() {
    generic_add_0(1.0, 2.0);
    generic_add_1(1.0, &2.0);
    generic_add_2(&1.0, 2.0);
    generic_add_3(&1.0, &2.0);
}

 类似资料:
  • 我有一个有界泛型类,我们称之为泛型,它的参数T扩展了抽象类abstract: 泛型类: 抽象类 泛型类中T引用的类 当尝试引用方法 getMap() 时,该方法来自 T 边界内的类(并且根据抽象类定义,T 的所有可能实例都将具有该方法),我收到以下错误: 不能从静态上下文引用非静态方法getMap() 然而,任何地方都没有静态关键字。我错过了什么?? 谢谢!

  • 我试图实现一个接受泛型参数的函数定义,只要它扩展了另一个特定的泛型类型。简言之参数A必须扩展参数B,其中A和B都是泛型的。 下面是我的示例 用法示例如下 一些封闭的班级 和函数调用 我不想在抽象类声明中定义E,因为T已经在那里定义了。 我也试着做了以下几点: 将myList定义为接受扩展T的键 将E定义为T类型(无法找到如何指定它在函数中扩展T 但它从来都不起作用。有没有办法做到这一点?我在Sta

  • 我正在尝试有一个通量通用转换器使用通用类型在Java 8。我把我的代码建立在这个答案的基础上。其思想基本上是实现这个特定的转换器->: 类型转换器->转换为我想要的任何类型。因此,我正在使用构造函数创建一个类型为的类,并返回一个方法。我想在调用上创建类似这样的多个条目:,但类类型不同。但它甚至对整数也不起作用。 当我使用此单元测试进行测试时,我得到错误:。

  • 我有大约40个API,它们具有类似的基本响应结构,如下所示: 因此,我有一个基本响应类,采用T类型的泛型,如下所示: 因此,对于API A,它返回类型为的对象及其自己的字段,我将返回响应作为控制器中的API响应: 在控制器中:响应数据=新响应();ResponseEntity response=新的ResponseEntity 在swagger中有没有一种方法可以递归地指定响应对象的模型?例如,我

  • 我在我的一个实用程序类中有一个方法,它接受一个集合和一个类对象,并返回一个Iterable实例,该实例可以遍历作为指定类实例的集合的所有成员。其签名为: 这对于大多数用例都非常有效,但现在我需要将其与泛型类

  • 我的目标是为CRUD操作使用一个通用类,这样我就不需要为我的应用程序中的每个域模型实现一个单独的类。 该层还在我的DTO和域模型之间进行转换。 get和delete方法工作正常。但是,如何实现save方法。对于新实体,我需要创建泛型的新实例,并将DTO映射到泛型上。 我的Service类如下所示: