【问题标题】:Why isn't this Scala implicit conversion working?为什么这个 Scala 隐式转换不起作用?
【发布时间】:2011-11-08 03:26:09
【问题描述】:

更新:我已经接受了答案,但我仍然很好奇为什么我尝试的方法不起作用(以了解 Scala 隐式行为)。任何其他答案将不胜感激。

(希望这个问题在没有太多 Circumflex 知识的情况下可以回答,但以防万一,here's 记录的源代码参考。)

我正在尝试在 Circumflex ORM 库上添加一些便利功能,但在尝试使用 Scala 隐式转换时遇到了一些障碍。下面,为什么隐式转换不触发?我怀疑与子类化和/或递归类型参数存在一些复杂的交互。

import ru.circumflex.orm._

// I subclass Record and Table to add my own convenience methods etc. (not pasted, irrelevant)
abstract class XRecord[PK, R <: XRecord[PK, R]] extends Record[PK, R] { this: R => }
trait XTable[PK, R <: XRecord[PK, R]] extends Table[PK, R] { this: R => }

// Example entity.
class Org extends XRecord[Long,Org] {
  val id = "id".BIGINT.NOT_NULL.AUTO_INCREMENT
  def PRIMARY_KEY = id
  def relation = Org
}
object Org extends Org with XTable[Long,Org]

object Test extends App {
  // I want this conversion to work for all Records, not just XRecords.
  // Need implicit f to be able to accept XRecord, a subclass of Record.
  implicit def toRichRelationNode[PK, R <: Record[PK,R], RR](xs: RR)(implicit f: RR => RelationNode[PK,R]) =
    new { def GET(f: RelationNode[PK,R] => Predicate) = 0 }

  // This works.
  toRichRelationNode(Org) GET (_.id EQ 1)

  // This doesn't:
  // "No implicit view available from Org.type => ru.circumflex.orm.RelationNode[PK,R]."
  Org GET (_.id EQ 1)
}

【问题讨论】:

  • 不确定在这种情况下会有所帮助,但通常建议指定隐式转换的返回类型。另外,回答new { def GET(f: RelationNode[PK,R] =&gt; Predicate) = 0 }是什么类型的问题可能会帮助您解决问题。
  • @Jamil 显式指定返回类型并将匿名类提升到命名类中没有任何区别。
  • 这真的是演示问题所需的最少代码吗?
  • @SethTisue 好吧,了解相关的确切交互是我困惑的一半。如果您有任何建议,我很乐意修改。

标签: scala implicit-conversion circumflex-orm


【解决方案1】:

坦率地说,我从来没有使用过隐式参数,也从来没有遇到过强迫我使用它们的条件(Circumflex 本身没有隐式参数,就我而言,效果很好)。

无论如何,我已经能够重现您的场景并使其发挥作用。然而,它需要 2 次隐式才能使一切顺利。代码如下:

// The helper which holds custom methods, it will accept any subclass of R
class NodeHelper[PK, R <: Record[PK, R]](val node: RelationNode[PK, R]) {
  def GET(f: R => Predicate): Option[R] = node.criteria.add(f(node)).unique()
} 

// Now the implicits and usage scenario

object Tester {

  implicit def nodeToHelper[PK, R <: Record[PK, R]](node: RelationNode[PK, R]): NodeHelper[PK, R] = new NodeHelper(node)

  implicit def tableToHelper[PK, R <: Record[PK, R]](table: Table[PK, R]): NodeHelper[PK, R] = new NodeHelper(table.AS("this"))

  // Testing with table
  println(User GET (_.cn EQ "patrick"))
  // Testing with node
  println(User.AS("u") GET (_.cn EQ "patrick"))
}

// And finally, the test model we've mentioned above

class User extends Record[Long, User] {
  def PRIMARY_KEY = id
  val id = "id".BIGINT.NOT_NULL.AUTO_INCREMENT
  val cn = "cn".TEXT.NOT_NULL
  def relation = User
}

object User extends User with Table[Long, User]

希望对你有帮助。

【讨论】:

  • 我想我主要是好奇为什么两个隐式是必要的,为什么原来的不起作用。我会将此答案标记为已接受,但我很想听听对此的任何其他答案/见解!
猜你喜欢
  • 1970-01-01
  • 2013-09-28
  • 1970-01-01
  • 2018-11-19
  • 2011-02-12
  • 2021-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多