亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 Java 解釋器中抽象數學運算

在 Java 解釋器中抽象數學運算

楊__羊羊 2023-06-14 10:39:13
我正在用 Java 編寫一個 AST 解釋器,它有很多方法可以檢查參數類型并在它們匹配時執行操作。到目前為止,已經有五種以上的方法,它們基本上是相互復制粘貼的版本。有沒有辦法抽象要檢查的類型和要執行的操作?    @Override    public Object visitMultiplyNode(MultiplyNode multiplyNode) {        Object lhs = multiplyNode.getLeftHandSide().accept(this);        Object rhs = multiplyNode.getRightHandSide().accept(this);        if (lhs instanceof Double && rhs instanceof Double) {            return (double) lhs * (double) rhs;        }        if (lhs instanceof Long && rhs instanceof Long) {            return (long) lhs * (long) rhs;        }        throw new TypeError("Can not multiply " + lhs.getClass() + " and " + rhs.getClass() + ".");    }我要檢查的類型并不總是相同的,例如,模數節點只接受 Longs 而加法節點也接受 Strings 進行連接。    @Override    public Object visitAddNode(AddNode addNode) {        Object lhs = addNode.getLeftHandSide().accept(this);        Object rhs = addNode.getRightHandSide().accept(this);        if (lhs instanceof Double && rhs instanceof Double) {            return (double) lhs + (double) rhs;        }        if (lhs instanceof Long && rhs instanceof  Long) {            return (long) lhs + (long) rhs;        }        if (lhs instanceof String && rhs instanceof String) {            return "" + lhs + lhs;        }        throw new TypeError("Can not add " + lhs.getClass() + " and " + rhs.getClass() + ".");    }    @Override    public Object visitModulusNode(ModulusNode modulusNode) {        Object lhs = modulusNode.getLeftHandSide().accept(this);        Object rhs = modulusNode.getRightHandSide().accept(this);        if (lhs instanceof Long && rhs instanceof Long) {            return (long) lhs % (long) rhs;        }        throw new TypeError("Can not take modulus of " + lhs.getClass() + " and " + rhs.getClass() + ".");    }
查看完整描述

2 回答

?
慕運維8079593

TA貢獻1876條經驗 獲得超5個贊

你可以使用 lambda:


private Object visitBinaryOperatorNode(BinaryOpNode node, BiFunction<T, T> op) {

    Object lhs = node.getLeftHandSide().accept(this);

    Object rhs = node.getRightHandSide().accept(this);


    if (lhs instanceof Long && rhs instanceof Long) {

        return op.apply((long) lhs, (long) rhs);

    }

    throw new TypeError("Can not take " + node.getOpName() + "of " + lhs.getClass() + " and " + rhs.getClass() + ".");

}

但是,由于您的某些運算符支持多種類型,因此您需要另一層抽象:


@RequiredArgsConstructor// Lombok, otherwise write the boilerplate yourself

public class BinaryOperator<T, T> {

   @NonNull private final BiFunction<T, T> op;

   @NonNull private final Class<T> clazz;


   public boolean isApplicable(Object left, Object right) {

       return clazz.isInstance(left) && clazz.isInstance(right);

   }


   public T apply(Object left, Object right) {

       return op.apply(clazz.cast(left), clazz.cast(right));

   }

}

您現在可以傳遞一組有效的二元運算符并測試它們是否適用,如果適用,則應用它們。


private static final List<BinaryOperator<?, ?>> VALID_ADD_OPERATORS = Arrays.asList(

    new BinaryOperator<>((x, y) -> x + y, Double.class), 

    new BinaryOperator<>((x, y) -> x + y, Long.class),

    new BinaryOperator<>((x, y) -> x + y, String.class)

);


private static final List<BinaryOperator<?, ?>> VALID_MULTIPLY_OPERATORS = Arrays.asList(

    new BinaryOperator<>((x, y) -> x * y, Double.class), 

    new BinaryOperator<>((x, y) -> x * y, Long.class)

);


@Override

public Object visitAddNode(AddNode addNode) {

    return visitBinaryOperatorNode(addNode, VALID_ADD_OPERATORS );

}


@Override

public Object visitMultiplyNode(MultiplyNode multiplyNode) { 

    return visitBinaryOperatorNode(multiplyNode, VALID_MULTIPLY_OPERATORS ); 

}


private Object visitBinaryOperatorNode(BinaryOpNode node, List<BinaryOperator<?, ?>> validOperators) {

    Object lhs = node.getLeftHandSide().accept(this);

    Object rhs = node.getRightHandSide().accept(this);


    for (BinaryOperator<?, ?> op : validOperators) {

        if (op.isApplicable(lhs, rhs)) return op.apply(lhs, rhs);

    }

    throw new TypeError("Can not take " + node.getOpName() + "of " + lhs.getClass() + " and " + rhs.getClass() + ".");

}


查看完整回答
反對 回復 2023-06-14
?
慕的地8271018

TA貢獻1796條經驗 獲得超4個贊

您可以將這些檢查提取到單獨的對象中,并在需要時重用它。

例如,通過為要處理轉換的每種類型定義一個枚舉值。


例如


public enum ConvertType {


    DOUBLE {

        Object apply(Object lhs, Object rhs) {

            if (lhs instanceof Double && rhs instanceof Double) {

                return (double) lhs + (double) rhs;

            }

            return null;

        }

    },


    LONG {

        Object apply(Object lhs, Object rhs) {

            if (lhs instanceof Long && rhs instanceof Long) {

                return (long) lhs + (long) rhs;

            }

            return null;

        }

    },


    STRING {

        Object apply(Object lhs, Object rhs) {

            if (lhs instanceof String && rhs instanceof String) {

                return "" + lhs + lhs;

            }

            return null;

        }

    };


    public static Object apply(Object a, Object b, ConvertType... convertTypes) {

        for (ConvertType convertType : convertTypes) {

            Object result = convertType.apply(a, b);

            if (result != null) {

                return result;

            }

        }

        throw new TypeError("Can not take modulus of " + a.getClass() + " and " + b.getClass() + ".");


    }


}

轉換的入口點是靜態方法:


public static Object apply(Object a, Object b, ConvertType... convertTypes)

ConvertType多虧了var-args.


例如 :


@Override

public Object visitMultiplyNode(MultiplyNode multiplyNode) {

    Object lhs = multiplyNode.getLeftHandSide().accept(this);

    Object rhs = multiplyNode.getRightHandSide().accept(this);        

    return ConvertType.apply(lhs , rhs, ConvertType.DOUBLE, ConvertType.LONG);

}

或者 :


@Override

public Object visitAddNode(AddNode addNode) {

    Object lhs = addNode.getLeftHandSide().accept(this);

    Object rhs = addNode.getRightHandSide().accept(this);

    return ConvertType.apply(lhs , rhs, ConvertType.DOUBLE, ConvertType.LONG, ConvertType.STRING);    

}


查看完整回答
反對 回復 2023-06-14
  • 2 回答
  • 0 關注
  • 171 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號