Scala:如何通过函数对象参数实现签名不同的通用流程?

Posted

技术标签:

【中文标题】Scala:如何通过函数对象参数实现签名不同的通用流程?【英文标题】:Scala: how to implement via function object parameters a generic flow where signatures differ? 【发布时间】:2015-04-12 20:23:20 【问题描述】:

我是一名 Java 程序员,在 Scala 编程中迈出了第一步。

我已经定义了一个类似的函数(这可能是惯用错误,我不知道...):

def someGenericAlgorithm(param1: String, param1: String, param3: String) = 

    val triedResult1 = someFunction(param1)
    triedResult1 match 
      case Success(result1) =>
        val triedResult2 = someOtherFunction(param2)
        triedResult2 match 
          case Success(result2) =>
            val triedPolymorphicResult = someToBeReplacedAccordingToSpecificLogicFunction(result1, result2, param3)
            triedPolymorphicResult match 
              case Success(polymorphicResult) =>
                doSomethingGeneric(polymorphicResult)                    
                ....
              case Failure(exception) =>
                ....
            
          case Failure(exception) =>
            ....
        
      case Failure(exception) =>
        ....
    
  

因此该函数接收 3 个参数,依次处理前两个参数,获取处理结果并将其与第三个参数一起传递给 someToBeReplacedAccordingToSpecificLogicFunction

现在我想写一个类似的函数,前两个函数调用都存在,错误逻辑是一样的,唯一的区别是someToBeReplacedAccordingToSpecificLogicFunction现在改为aReplacementLogicFunction

如果这两个函数有相同的签名,我想这不会是一个问题,但是,他们没有,aReplacementLogicFunction 有不同的参数,更具体地说,还有两个参数。你可能会说,我可以只传入Option 参数,其中这两个Options 在第一种情况下是Nones,这样我就可以将我的两个函数对齐为相同的签名,因此:

def someToBeReplacedAccordingToSpecificLogicFunction(result1: Int, result2: Int, param3: String, unused1:Option[String] = None, unused2:Option[String] = None)

def aReplacementLogicFunction(result1: Int, result2: Int, param3: String, used1:Option[String], used2:Option[String])

但是,存在第三个流程,其中第一个函数的不存在参数属于不同类型,例如 MyClass,例如:

def anotherReplacementLogicFunction(result1: Int, result2: Int, param3: String, used1: MyClass, used2: MyClass)

问题是,那么,我将如何生成这些函数以传递给一些重构的通用算法函数,该函数将接收一个函数作为参数。有没有办法定义类似的东西:

def refactoredOutCoreLogic(param1: String, param1: String, param3: String, polimorphicFunction: SignatureUnknown)

Java 回答我自己的问题:

我在 Java 中解决这个问题的方法是定义一个类层次结构,类似于:

abstract class ResultKeeperRunnable implements Runnable 
    protected int param1, param2;
    void setParam1(...) ...
    void setParam2(...) ...


class SomeToBeReplacedAccordingToSpecificLogicFunctionClass extends ResultKeeperRunnable  
    String param3;
    // ctor receiving all params omitted for brevity 
    void run() 
      // do specific Logic
    


class AReplacementLogicFunctionClass extends ResultKeeperRunnable 
    String param3, param4, param5;
    // ctor receiving all params omitted for brevity 
    void run() 
      // do specific Logic
    


class AnotherReplacementLogicFunctionClass extends ResultKeeperRunnable 
    String param3;
    MyClass param4, param5;
    // ctor receiving all params omitted for brevity 
    void run() 
      // do specific Logic
    

最后分解出来的核心逻辑方法是这样的:

void refactoredOutCoreLogic(String param1, String param2, String param3, ResultKeeperRunnable polimorphicLogic) 
    // error handling logic removed for brevity
    int result1 = someMethod(param1);
    int result2 = someOtherMethod(param2);
    polymorphicLogic.setParam1(result1);
    polymorphicLogic.setParam2(result2);
    polymorphicLogic.run()
    ...


Scala 解决方案将不再是上述 Java 解决方案的语法不同的克隆吗?似乎应该有一个更优雅的解决方案。

【问题讨论】:

【参考方案1】:

拥有一个函数,该函数接受result1result2 和一堆其他参数。

想要一个只接受result1result2的函数。

为此,请使用partial application。编写你的可替换函数,像这样在末尾加上第二组括号,保存公共参数:

def aReplacementLogicFunction(param3: String, used1:Option[String], used2:Option[String])(result1: Int, result2: Int)

然后将部分应用的函数传递给你的通用函数,如下所示:

someGenericAlgorithm(param1, param2, aReplacementLogicFunction(param3, used1, used2))

就通用算法而言,它完全不知道额外的参数。这些都是在调用函数之前应用的。

【讨论】:

感谢@Karl,这是一个美丽而优雅的解决方案!

以上是关于Scala:如何通过函数对象参数实现签名不同的通用流程?的主要内容,如果未能解决你的问题,请参考以下文章

Scala 中是不是有与 Python 更通用的 map 函数等价的功能?

如何创建具有可变参数/不同方法签名的方法接口?

scala函数

Scala学习笔记(函数相关)

js重载

Scala中的构造器与对象文末加群学习哦