機能

2016-04-08 9 views
0

私は、同じ符号化パターンを持ついくつかの機能を持っている:私のコードは少なく、私は機能

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") 
    } 
} 

などの新しいプライベート関数を記述繰り返し行うために

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") 
    } 
} 

trait DomainObject { ... } 

case class Foo(...) extends DomainObject { ... } 

しかし、上記の変更により、私はupdateFooValidationStatusの内部でupdateDomainObjectValidationStatusを呼び出すことはできません。 n個の1つのパラメータ興味深いことに

type mismatch, expected (DomainObject) => Option[DomainObject], actual (Foo) => Option[Foo] 

上の誤り、それは

(Long) => Option[Foo] 

をとり、最初のパラメータ

(Long) => Option[DomainObject] 

を文句はありませんScalaでは、コードのデザインになりますどのような慣用的なファッションへ上記のコードを動作させる?ここでは何が起こる

+0

'def'sは機能ではありません、それらのメソッドです – pedrofurla

答えて

4

は次のとおりです。関数は、引数のタイプ(複数可)およびその戻り値の型共変反変あるためupdateDomainObjectValidationStatusは、タイプ(DomainObject) => Option[DomainObject]の引数としてタイプ(Foo) => Option[Foo]で値を受け入れることはできません。どういう意味ですか? ABを拡張

  • 場合、Aを返す関数Bを返す関数を拡張
  • しかしAは、と、関数をB拡張する場合、(コンパイラはあなたの最初のパラメータ文句はありません理由です)引数Bの場合は、引数がAの関数を拡張します。つまり、逆の意味です。

なぜ意味がありますか?

考えてみましょう:A extends Bとすれば、「AはBです」と言うことができます。今、「Aの関数」はAで動作しますが、必ずしもBにあるとは限りません。あなたの関数がInt引数を持っていれば、AnyVal型の値を渡すことはできません...逆は働きます - AnyValの関数をIntで呼び出すことは間違いありません。

は、この問題を修正するには - 最善のアプローチはupdateDomainObjectValidationStatusDomainObject拡張タイプ与えることであろうように、この場合には、なります。あなたがタイプ(Long) => Option[Foo]の最初のパラメータでそれを呼び出すと

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

を、タイプTFooであると推定され、次にコンパイラは予想通りに第3世代に対して(Foo) => Option[Foo]を予期します。素晴らしいボーナスも得られます。戻り値の型はOption[DomainObject]ではなくOption[Foo]のように、より具体的になります。

+0

詳細な説明はありがとうございます。変更のために、私はDomainObject特性とそのサブケースクラスをパラメータ化する必要があります。この特性にはメソッドシグネチャが定義されています。かなりの修正を行った後、私はそれを解決する必要があります。 – TeeKai