简体   繁体   English

Scala类型类和隐式难题

[英]Scala typeclass and implicit puzzle

The last statement line below produces an error: "type mismatch; found: TestExpandableWithLibrary.this.library.type (with underlying type org.typeclass.Library) required: V" 下面的最后一条语句行产生错误:“类型不匹配;找到:TestExpandableWithLibrary.this.library.type(具有基本类型org.typeclass.Library):V”

This is where I am trying to do an implicit conversion. 这是我尝试进行隐式转换的地方。 The preceding line where I simply use the typeclass function does work fine. 我仅使用typeclass函数的前一行工作正常。

Any ideas on how to fix it? 关于如何解决它的任何想法?

package org.typeclass

///////////////////////////////////////////////////////////////////////////////
// the domain objects

case class Book(bookName: String)

case class Library(libraryName: String, books: Set[Book])

object Library {
  def apply(libraryName: String, bookNames: String*): Library =
    Library(libraryName, bookNames.map(Book(_)).toSet)
}

case class TreeClass(nodeName: String, children: Seq[TreeClass])

///////////////////////////////////////////////////////////////////////////////
// the typeclass definition

trait Expandable[T, V, R] {
  def expandWith(template: T, values: V): R
}

object Expandable {

  def expandWithF[T, V, R](template: T, values: V)(implicit ev: Expandable[T, V, R]): R =
    ev.expandWith(template, values)

  implicit class ExpandableItem[T, V, R](val template: T) extends AnyVal {
    def expandWithM(values: V)(implicit ev: Expandable[T, V, R]): R =
      ev.expandWith(template, values)
  }
}

///////////////////////////////////////////////////////////////////////////////
// a typeclass implementation

object ExpandableImpls {

  implicit object ExpandableTreeClass extends Expandable[TreeClass, Library, TreeClass] {
    def expandWith(template: TreeClass, library: Library): TreeClass = {
      val parentName = s"${template.nodeName}.${library.libraryName}"
      val children = library.books.map(book => TreeClass(s"${parentName}.${book.bookName}", Seq.empty)).toSeq
      TreeClass(parentName, children)
    }
  }

}

//@RunWith(classOf[JUnitRunner])
class TestExpandableWithLibrary /*extends FlatSpec*/ {

  import Expandable._
  import ExpandableImpls._

  val library = Library("test", "black", "white")
  val root = TreeClass("parent", Seq.empty)

  val useF = expandWithF(root, library) // this works

  val useM = root.expandWithM(library) // this doesn't work!

}

The problem is just that you need to put the second two type parameters on the implicit class on the extension method—as it is they'll be inferred to be Nothing , since they're not referred to in the constructor arguments. 问题在于,您需要将第二个两个类型参数放在扩展方法的隐式类上,因为它们会被推断为Nothing ,因为在构造函数参数中未引用它们。

implicit class ExpandableItem[T](val template: T) extends AnyVal {
  def expandWithM[V, R](values: V)(implicit ev: Expandable[T, V, R]): R =
    ev.expandWith(template, values)
}

This should work just fine. 这应该很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM