Scala 作为参数的函数

Scala 作为参数的函数,scala,Scala,我有几个具有相同编码模式的函数: def updateFooValidationStatus(fooId: Long, user: String, valid: Boolean): Option[Foo] = { val fooMaybe = fooDao.getFooById(activityId) fooMaybe match { case Some(foo) => { fooDao.update(foo.copy(updatedBy = Some(use

我有几个具有相同编码模式的函数:

def updateFooValidationStatus(fooId: Long, user: String, valid: Boolean): Option[Foo] = {

  val fooMaybe = fooDao.getFooById(activityId)
  fooMaybe match {
    case Some(foo) => {
      fooDao.update(foo.copy(updatedBy = Some(user),
        validationStatus = if (valid) Some(DataEntryValidationStatus.Valid) else Some(DataEntryValidationStatus.Invalid))
    )
   }
   case None =>
    throw new DomainException(s"Foo with ID: '$fooId' doesn't exist")
  }
}
为了减少代码的重复,我编写了一个新的私有函数

private def updateDomainObjectValidationStatus(f1: Long => Option[DomainObject],
               parameter1: Long,
               f2: DomainObject => Option[DomainObject],
               paramter2: String,
               valid: Boolean ): Option[DomainObject] ={

  val somethingMaybe = f1(parameter1)
  somethingMaybe match {
    case Some(something) =>
      f2(
        something.copyMe(updatedBy = Some(paramter2),
        validationStatus = if(valid) Some(DataEntryValidationStatus.Valid) else Some(DataEntryValidationStatus.Invalid))
      )
    case None =>
      throw new DomainException(s"Object with ID: '$parameter1' doesn't exist")
  }
}
在哪里

但是,通过上述更改,我无法在UpdateFovalidationStatus内部调用updateDomainObjectValidationStatus,因为一个参数上存在错误

type mismatch, expected (DomainObject) => Option[DomainObject], actual (Foo) => Option[Foo]
(Long) => Option[DomainObject]
有趣的是,它并没有抱怨第一个参数

type mismatch, expected (DomainObject) => Option[DomainObject], actual (Foo) => Option[Foo]
(Long) => Option[DomainObject]
这需要

(Long) => Option[Foo]

按照Scala的惯用方式,什么样的代码设计才能使上述代码正常工作?

这里发生的是:
updateDomainObjectValidationStatus
不能接受类型为
(Foo)=>Option[Foo]
的值作为类型为
(DomainObject)=>Option[DomainObject]
的参数,因为函数的参数类型是逆变的,返回类型是协变的。这是什么意思

  • 如果
    A
    扩展
    B
    ,那么返回
    A
    的函数将扩展返回
    B
    的函数(这就是为什么编译器不会抱怨您的第一个参数)
  • 但是,如果
    A
    扩展
    B
    ,则带有
    B
    类型参数的函数将扩展带有
    A
    类型参数的函数,意思是相反的
这有什么意义

想想看:如果A扩展了B,我们可以说“A是B”。现在,“a上的函数”可以在任何
a
上工作,但不一定在任何
B
上工作,对吗?如果函数具有
Int
参数,则不能使用
AnyVal
类型传递值。。。与此相反的是,可以使用
Int
调用
AnyVal
上的函数

要解决此问题-在本例中,最好的方法似乎是为
updateDomainObjectValidationStatus
提供一个扩展
DomainObject
的类型:

private def updateDomainObjectValidationStatus[T <: DomainObject](
   f1: Long => Option[T],
   parameter1: Long,
   f2: T => Option[T],
   paramter2: String,
   valid: Boolean): Option[T] = { ... } 
private def updateDomainObjectValidationStatus[T选项[T],
参数1:长,
f2:T=>选项[T],
参数2:字符串,
有效:布尔):选项[T]={…}

当您使用类型为
(Long)=>Option[Foo]
的第一个参数调用它时,类型
T
被推断为
Foo
,然后编译器期望第三个参数使用
(Foo)=>Option[Foo]
,正如预期的那样。您甚至可以得到一个不错的奖励-返回类型将更加具体:
Option[Foo]
而不是
选项[DomainObject]

这里发生的是:
更新的MainObjectValidationStatus
不能接受类型为
(Foo)=>选项[Foo]
的值作为类型为
(DomainObject)=>选项[DomainObject]
的参数,因为函数的参数类型是相反的它们的回报类型是协变的。这是什么意思

  • 如果
    A
    扩展
    B
    ,那么返回
    A
    的函数将扩展返回
    B
    的函数(这就是为什么编译器不会抱怨您的第一个参数)
  • 但是,如果
    A
    扩展
    B
    ,则带有
    B
    类型参数的函数将扩展带有
    A
    类型参数的函数,意思是相反的
这有什么意义

想想看:如果
A扩展了B
,我们可以说“A是B”。现在,“A上的函数”可以在任何
A
上工作,但不一定在任何
B
上工作,对吗?如果您的函数有
Int
参数,则不能使用
AnyVal
类型传递值……相反的情况确实有效-可以使用
Int
调用
AnyVal
上的函数

要解决此问题-在本例中,最好的方法似乎是为
updateDomainObjectValidationStatus
提供一个扩展
DomainObject
的类型:

private def updateDomainObjectValidationStatus[T <: DomainObject](
   f1: Long => Option[T],
   parameter1: Long,
   f2: T => Option[T],
   paramter2: String,
   valid: Boolean): Option[T] = { ... } 
private def updateDomainObjectValidationStatus[T选项[T],
参数1:长,
f2:T=>选项[T],
参数2:字符串,
有效:布尔):选项[T]={…}

当您使用类型为
(Long)=>Option[Foo]
的第一个参数调用它时,类型
T
被推断为
Foo
,然后编译器期望第三个参数使用
(Foo)=>Option[Foo]
,正如预期的那样。您甚至可以得到一个不错的奖励-返回类型将更加具体:
Option[Foo]
而不是
选项[DomainObject]

def
s不是函数,它们是方法
def
s不是函数,它们是方法非常感谢详细的解释。对于更改,我需要参数化DomainObject特性及其子案例类。特性中定义了一个方法签名。我需要在几分钟后解决它修复。非常感谢您的详细解释。对于更改,我需要参数化DomainObject trait及其子案例类。trait中定义了一个方法签名。我需要在多次修复后计算出它。