【问题标题】:implicit param and overloading gotcha隐式参数和重载问题
【发布时间】:2012-10-05 18:17:49
【问题描述】:
trait DAOContract[T <: Entity] {
  // default create
  def create(t: T): Option[Int]
}

trait UserContract extends DAOContract[User] {
  // provide alternate create method for transactional blocks
  def create(u: User)(implicit ss: Session): Either[String, Int]
  ...
}

// DAO provides create implementation with embedded session
class UserDAO(implicit val db: Connection) 
  extends DAO[User] with UserContract {

  import db.Driver.Implicit._
  import org.scalaquery.ql._
  ...
}

在控制器中

dao.create(model) // boom, no implicit session

我希望我在这里遗漏了一些东西:为什么 scala 编译器无法区分上面的 2 个创建方法签名?

基本上,如果不对事务性(即返回 Either)或独立的操作提出不同的方法命名约定,我就不可能重载 DAO 操作。

或者,我只是以错误的方式处理事情,完全有可能......

【问题讨论】:

  • 您能否提供一段我们可以编译和使用的独立代码?
  • 不是直接用所有的管道,而是试试这个代码sn-p,捕获问题:“pastebin.com/KvWA1hDv” 似乎隐式参数启用的方法需要不同的签名;换句话说,afaik,不可能超载,否则很高兴听到/看到解决方法

标签: scala overloading implicit


【解决方案1】:

Scala 禁止这样做是有原因的:

  1. 想象一下,您的 create 方法是:

    def create(t: User): Function[Int,Something]
    def create(u: User)(implicit ss: Session): Either[String, Int]
    

    然后调用create(x)(y) 将适用于他们两个。

  2. 即使 (1.) 中的问题可以通过 Scala 编译器仔细检查函数的类型来解决,还是很容易出错。在这样的设置中,程序员很容易出错。为函数强制使用不同的名称可确保程序员始终知道他们调用的是什么。


如果将您的方法更改为具有相同的返回类型,并且如果您愿意采取冒险的方式,您可以尝试以下方法:

trait Broken {
  final def foo(x: Int)(implicit session: String = null): Option[Int] =
    if (session == null) foo1(x)
    else foo2(x, session);

  def foo1(x: Int): Option[Int]
  def foo2(x: Int, session: String): Option[Int]
}
class Example extends Broken {
  def foo2(x: Int, y: String) = Some(2)
  def foo1(x: Int) = Some(1)
}

object Test extends App {
  def withImplicit(e: Example) = {
    implicit val imp = "hey"
    e.foo(1) // (imp)
  }
  def withoutImplicit(e: Example) = e.foo(1)

  println(withImplicit(new Example()));
  println(withoutImplicit(new Example()));
}

当一个隐式值可用时,调用相应的方法。否则,调用没有“会话”参数的方法。但我强烈不鼓励这种方法。只是一个小错误就会导致调用错误的变体,这将很难调试。

【讨论】:

  • +1,很好的解释,彼得。现在我采取了安全的方法并将默认 DAO 方法重命名为 createOne、updateOne 和 deleteOne(尽管您的解决方法很诱人,因为我可以做我想做的事,保留 DAO 命名空间)。大多数持久性操作发生在事务块中,因此使用隐式会话参数创建、更新、删除保留用于可回滚操作,其中会话隐式传递到事务块“db.withSession {implicit ss:Session => ss.withTransaction{ for{//DAO 调用这里 } }}"
【解决方案2】:

您的创建方法有不同的信号。一个返回一个 Either,另一个返回一个 Option。加上隐含的。您可能需要隐式使用并从两者返回一个 Option[Int]

【讨论】:

  • 我需要对于 for{...} 事务块,该块穿过正确的投影
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多