如何制作一个比较任意数量的相同类型的通用 lambda

Posted

技术标签:

【中文标题】如何制作一个比较任意数量的相同类型的通用 lambda【英文标题】:How to make a generic lambda that compares any Number of identical type 【发布时间】:2021-11-22 23:52:37 【问题描述】:

我需要在运行时替换比较运算符,其中两个数字将被比较 GreaterThanOrEquals、LessThanOrEquals、Equals 等,但理想情况下,我不会为整数、双精度、长整数、短整数、浮点数和字节复制我的代码.我的部分要求是尽可能将操作保持在 lambdas 中以提高性能。

注意:这两个值总是相同的类型。我无意进行混合类型的比较。

这是我的粗略代码。我试图用 Java.lang.Number 参数化最后一个静态方法,但 >= 对 Number 不起作用:

public class Expression 
    public Param p1;
    public Operator o;
    public Param p2;

    public Object eval() 
        return o.eval(p1.getValue(),p2.getValue());
    



public interface Operator<T>
    Object eval(T p1,T p2);



public interface GreaterOrEqual extends Operator<Number>
    static Operator<Integer> Integers() 
        return (v1, v2) -> v1 >= v2;
    

    static Operator<Double> Doubles() 
        return (v1, v2) -> v1 >= v2;
    

    static Operator<Long> Longs() 
        return (v1, v2) -> v1 >= v2;
    

    static Operator<Number> generic() 
        // this one won't compile as ">= can't be applied to Java.lang.Number"
        return (v1, v2) -> v1 >= v2;
    


编辑:此代码重复也意味着我的 GUI 代码将需要使用 if (Param.value instanceof Integer) Expression.setOperator(GreaterOrEqual.Integers);,这是更多的代码重复。

【问题讨论】:

你可以做v1.doubleValue() &gt;= v2.doubleValue() 这不是性能慢吗?将每个值转换为双精度值?要求之一是高性能......可能在几微秒内反复运行......取决于当前负载。 Operator的意图是什么?从eval返回Object背后的想法是什么? Operator 是一个接口,它的 children 赋予它的 lambda 功能,就像一个策略模式。 GUI 或文本解析器都将构建 Expression 对象。返回对象,因为根据操作,它可能需要是布尔值或整数/双精度(例如乘法运算符)。 【参考方案1】:

首先你必须明白,写Operator&lt;Integer&gt; 并没有给你带来任何好处。 Java 使用自动装箱将int 转换为Integer 包装对象。然后在您的代码 ((v1, v2) -&gt; v1 &gt;= v2) 中,Integer 对象被转换回 int

更通用的解决方案是使用Comparable 接口。 Number 没有实现该接口,但所有重要的 Number 实现如 Double 都支持它。

Operator<Comparable<?>> gt = (v1, v2) -> v1.compareTo(v2) > 0;
Operator<Comparable<?>> ge = (v1, v2) -> v1.compareTo(v2) >= 0;
Operator<Comparable<?>> ge = (v1, v2) -> v1.compareTo(v2) = 0;
Operator<Comparable<?>> le = (v1, v2) -> v1.compareTo(v2) <= 0;
Operator<Comparable<?>> lt = (v1, v2) -> v1.compareTo(v2) < 0;

compareTo 参数较小时返回 1,相同大小时返回 0,较大时返回 -1。

【讨论】:

哦,很高兴了解 Autoboxing。我用它来强制两个值属于同一类型……但我可以用其他方式强制它。所以 Comparable 不适用于 Integer,但适用于 Double、Long、Float?您认为我应该将 Int 转换为 Double 进行比较(如提到的@QBrute)吗? 它适用于所有包装类,包括IntegerintInteger 不一样。一个是对象,另一个是原始类型。【参考方案2】:

可比接口的使用

public static <T extends Comparable<? super T>> int compare(T x, T y) 
    return x != null ? x.compareTo(y) : -y.compareTo(x);

可能的结果

-1,当x 小于y 0,当x 等于y 1,当x 大于y

可能的用途

compare(x, y) &lt; 0 - x 小于 ycompare(x, y) &lt;= 0 - x 小于或等于 ycompare(x, y) == 0 - x 等于 ycompare(x, y) &gt;= 0 - x 大于或等于 ycompare(x, y) &gt; 0 - x 大于 y


如果有错误或问题,请通知我!

【讨论】:

以上是关于如何制作一个比较任意数量的相同类型的通用 lambda的主要内容,如果未能解决你的问题,请参考以下文章

打字稿:如何制作接受对象的类型,其键匹配通用但所有值都是值参数的映射函数

任意数量的通用参数

如何制作可变参数宏(可变数量的参数)

如何在 TypeScript 3+ 中正确键入通用元组剩余参数?

Python 3 类型,具有任意数量的包含类型的自定义可变参数泛型,如何?

MinIO的搭建