簡體   English   中英

Scala隱式轉換和參數

[英]Scala implicit conversions and parameters

我正在嘗試通過示例來解決《 Scala 》一書中的一個練習,該書的第15章隱式參數和轉換可以在此處找到:

並具有以下代碼示例:

object DemoImplicitConversions {
  def main(args: Array[String]) {
    val xs = List(new Num(1), new Num(4), new Num(2), new Num(6),new Num(3))
    val sortedXs = sort(xs)(num2ordered)
    print(sortedXs.mkString(","))
  }

  type OrderedView[A] = A => Ordered[A]

  // View bound : [A <% Ordered[A]] - means that sort is applicable to lists of type A such that there exists an
  // implicit conversion from A to Ordered[A]

  def sort[A: OrderedView](xs: List[A])(c: OrderedView[A]): List[A] =
    if (xs.isEmpty || xs.tail.isEmpty) xs
    else {
      val (ys, zs) = xs.splitAt(xs.length / 2)
      merge(ys, zs)(c)
    }

  def merge[A: OrderedView](xs: List[A], ys: List[A])(c: OrderedView[A]): List[A] =
    if (xs.isEmpty) ys
    else if (ys.isEmpty) xs
    else if (c(xs.head) < ys.head) xs.head :: merge(xs.tail, ys)(c)
    else ys.head :: merge(xs, ys.tail)(c)

  implicit def num2ordered(x: Num): Ordered[Num] = new Ordered[Num] {
    override def compare(y: Num): Int =
      if (x.value < y.value) -1
      else if (x.value > y.value) 1
      else 0

  }
}

case class Num(value: Int)  {
  override def toString: String = value.toString
}

不幸的是,我找不到一種隱式地將轉換器分配給方法排序的方法,以使客戶端代碼看起來像:

def main(args: Array[String]) {
    val xs = List(new Num(1), new Num(4), new Num(2), new Num(6),new Num(3))
    val sortedXs = sort(xs)
    printList(sortedXs)
  }

如果我為方法合並和排序的轉換器參數添加隱式關鍵字,則會得到

含糊的隱含值

編譯錯誤消息。

您對A施加的類型約束稱為上下文綁定 當您在注釋中正確書寫時, A : OrderedView意味着存在隱式值A[OrderedView] 您的錯誤是如何嘗試獲取該實例。 您將方法簽名寫為:

def merge[A: OrderedView](xs: List[A], ys: List[A])(c: OrderedView[A]): List[A]

但是,當使用上下文綁定時,它應該是:

def merge[A: OrderedView](xs: List[A], ys: List[A]): List[A]

然后使用implicitly運算符獲取所需的實例。 因此,您的方法可能類似於:

def sort[A: OrderedView](xs: List[A]): List[A] = (merge _).tupled(xs.splitAt(xs.length / 2))

def merge[A: OrderedView](xs: List[A], ys: List[A]): List[A] = {
  //This is how we get the c instance      
  val c = implicitly[OrderedView[A]] 
  ...
}

您的另一個選擇是擺脫上下文視圖,而改用隱式參數(然后在方法主體中不要implicitly使用):

def merge[A](xs: List[A], ys: List[A])(implicit c: OrderedView[A]): List[A]

這些是完全等效的。 實際上,上下文綁定在編譯過程中基本上已轉換為該版本。 通過使用上下文綁定使用另一個參數列表(盡管您不是隱式的,這是必需的),您正在混合這些習慣用法。

在您的示例中,您甚至都不需要顯式的OrderedView[A]實例。 由於它在隱式范圍內可用(由上下文綁定保證),因此在必要時會自動應用它。 因此,您甚至可以進一步簡化事情:

def merge[A: OrderedView](xs: List[A], ys: List[A]): List[A] =
    if (xs.isEmpty) ys
    else if (ys.isEmpty) xs
    //Here, the implicit conversion occurs on xs.head
    else if (xs.head < ys.head) xs.head :: merge(xs.tail, ys)
    else ys.head :: merge(xs, ys.tail)

另外,您可以在此處使用視圖綁定 ,而不是上下文綁定。 然后,您甚至不需要引入OrderedView類型別名:

def sort[A <% Ordered[A]](xs: List[A]): List[A]
def merge[A <% Ordered[A]](xs: List[A], ys: List[A]): List[A]
//Or, equivalently:
def sort[A](xs: List[A])(implicit ev: A => Ordered[A]): List[A]
def merge[A](xs: List[A], ys: List[A])(implicit ev: A => Ordered[A]): List[A]

在此處閱讀有關上下文范圍(和視圖范圍)的更多信息

作為不相關的說明,您還應該探索使用match語句,該語句在Scala中非常強大:

def merge[A <% Ordered[A]](xs: List[A], ys: List[A]): List[A] = (xs, ys) match {
      case (Nil, _) => ys
      case (_, Nil) => xs
      case (xhd::xtl, yhd::ytl) if xhd < yhd => xhd :: merge(xtl, ys)
      case (_, yhd::ytl) => yhd :: merge(xs, ytl)
}

這個定義:

def sort[A: OrderedView](xs: List[A])(c: OrderedView[A]): List[A]

實際上等於:

def sort[A](xs: List[A])(c: OrderedView[A])(implicit ev: OrderedView[A]): List[A]

也就是說,您的c: OrderedView[A]參數絕對獨立於上下文綁定,它只是另一個參數。

您只需要忽略上下文綁定:

def sort[A](xs: List[A])(implicit c: OrderedView[A]): List[A]

或省略參數:

def sort[A: OrderedView](xs: List[A]): List[A]

但是,在后一種情況下,如果要訪問隱式參數,則必須使用implicitly

implicitly[OrderedView[A]](xs.head)

也許您甚至不需要顯式調用它,因為隱式轉換將自動觸發。

暫無
暫無

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

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