簡體   English   中英

嘗試傳遞函數時,Scala類型不匹配

[英]Scala type mismatch while trying to pass a function

我需要一些幫助,試圖弄清楚如何重用我不想重復的模式匹配(如果可能)。 我在這里和Google進行過搜索,嘗試了隱式和方差,但到目前為止沒有任何結果。

在下面是兩種方法,doSomething和doSomethingElse在id上包含相同的模式匹配。 我想通過傳入一個函數來重用該模式。

這是初始設置。 (toPath和take2的實際實現並不真正相關。)

import java.nio.file.{Paths, Path}
import java.util.UUID

def take2(x: Long): String = {
    (x % 100).toString.padTo(2, '0')
}

def take2(u: UUID): String = {
    u.toString.take(2)
}

def toPath(x: Long): Path = {
    Paths.get(s"$x")
}

def toPath(u: UUID): Path = {
    Paths.get(u.toString)
}

case class Ids(id1: Option[Long], id2: Option[UUID])

def doSomething(ids: Ids): String = ids match {
    case Ids(_, Some(uuid)) => take2(uuid)
    case Ids(Some(long), _) => take2(long)
}

def doSomethingElse(ids: Ids) = ids match {
    case Ids(_, Some(uuid)) => toPath(uuid)
    case Ids(Some(long), _) => toPath(long)
}

doSomething(Ids(Some(12345L), None))
doSomethingElse(Ids(Some(12345L), None))

我想要的是這樣的事情:

def execute[A](ids: Ids)(f: Any => A): A = ids match {
    case Ids(_, Some(uuid)) => f(uuid)
    case Ids(Some(long), _) => f(long)
}

def _doSomething(ids: Ids) = execute[String](ids)(take2)
//def _doSomething2(ids: Ids) = execute[Path](ids)(toPath)

我得到的錯誤是:

Error: ... type mismatch;
 found   : (u: java.util.UUID)String <and> (x: Long)String
 required: Any => String
def _doSomething(ids: Ids) = execute[String](ids)(take2)
                                              ^                                          ^

請問如何使這些功能類型起作用?

我的Scala版本2.11.2。

我一直在使用的工作表: https : //github.com/lhohan/scala-pg/blob/0f1416a6c1d3e26d248c0ef2de404bab76ac4e57/src/main/scala/misc/MethodPassing.sc

任何幫助或指針,感激不盡。

問題是您有兩種不同的方法碰巧共享相同的名稱,例如“ take2”。 當您嘗試使用take2您肯定沒有提供可以處理任何參數類型的函數(如Any => A要求的)。 您甚至無法處理所需的兩種類型,因為它們是兩種不同的方法!

在原始的match語句中,您不會注意到這兩個方法是兩個共享相同名稱的方法,因為編譯器會根據參數類型填寫正確的方法。 沒有一個功能可以說:“插入我提供的名稱,然后使用其他方法”。 (嗯,您可以使用宏來做到這一點,但是要避免重復一點就太復雜了。)

現在,編譯器足夠聰明,做一個函數出你想要的方法。 所以如果你寫

def execute[A](ids: Ids)(f1: UUID => A, f2: Long => A): A = ids match {
  case Ids(_, Some(uuid)) => f1(uuid)
  case Ids(Some(long), _) => f2(long)
}

然后你可以

def doSomething(ids: Ids) = execute[String](ids)(take2, take2)

這會減少重復。

或者,您可以編寫

import scala.util._
def take2(x: Long): String = (x % 100).toString.padTo(2, '0')
def take2(u: UUID): String = u.toString.take(2)
def take2(ul: Either[UUID, Long]): String = ul match {
  case Left(u) => take2(u)
  case Right(l) => take2(l)
}

(如果在REPL中嘗試使用:paste ,請確保使用:paste ,以便將所有三個一起定義)。

然后你寫

def execute[A](ids: Ids)(f: Either[UUID, Long] => A): A = ids match {
  case Ids(_, Some(uuid)) => f(Left(uuid))
  case Ids(Some(long), _) => f(Right(long))
}

並且將使用三個take2的正確之一。 (與參數的額外裝箱相關的運行時懲罰,但是我懷疑這是對性能至關重要的代碼路徑。)

還有其他選項-例如Shapeless提供聯合類型。 或者,如果您傳遞的內容既不是UUID也不是Long ,則可以執行運行時模式匹配並拋出異常,但是以后可能會引起麻煩。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM