可以通过委托来满足scala自我类型吗?

时间:2013-09-19 13:58:59

标签: scala delegation implicits self-type

假设我(并且这是相当做作的)

trait DbConnection {
  val dbName: String
  val dbHost: String
}

class Query {
  self: DbConnection =>

  def doQuery(sql: String) {
    // connect using dbName, dbHost
    // perform query
  }
}

class HasADbConnection(override val dbName: String, 
                       override val dbHost: String) extends DbConnection {
  self =>

  def doSomething() {
    doSomethingElseFirst()
  }

  def doSomethingElseFirst() = {
    val query = new Query() with DbConnection {
      override val dbName = self.dbName
      override val dbHost = self.dbHost
    }
    query.doQuery("")
  }
}

有没有办法在新的Query()创建中避免冗余的“覆盖val dbName = self.dbName,覆盖val dbHost = self.dbHost”,而是指示新的Query对象应该从/ delegate继承这些字段的HasADbConnection实例?

我意识到Query可能更适合将DbConnection作为构造函数参数。我对其他方式满足Query自我类型感兴趣。也许没有办法将HasADbconnection字段传播到新的Query实例上,这是一个完全有效的答案。

1 个答案:

答案 0 :(得分:1)

不确定您要做什么,但这似乎与您的意图相匹配:

trait C extends B {
    def myA = new A() with C {  // Note that this could be "with B" rather than "with C" and it would still work.
        val name: String = C.this.name // explicit type not actually required - String type can be inferred.
    }
}

然后,例如:

scala> val myC = new C() { val name = "myC-name" }
myC: C = $anon$1@7f830771

scala> val anA = myC.myA
anA: A with C = C$$anon$1@249c38d5

scala> val aName = anA.name
aName: String = myC-name

希望这至少可以帮助指导您的最终解决方案。如果你进一步明确你想做什么(或者你想做什么),可能会给予进一步的帮助。

编辑 - 更新后提问:

我建议你可能会以错误的方式思考这个问题。我不想将Query类绑定到知道如何伪造连接。相反,要么将现成的连接作为参数传递给使用连接的调用,要么(如下所示)设置Query类以提供从连接到结果的函数,然后使用建立的连接调用该函数别处。

以下是我将如何解决此问题(请注意,此示例本身并不创建实际的数据库连接,我只是将DbConnection类型设置为面值 - 实际上您实际上已经定义了'DbConnConfig'类型) :

trait DbConnection {
  val dbName: String
  val dbHost: String
}


class Query(sql: String) {
  def doQuery: DbConnection => String = { conn: DbConnection =>
    // No need here to know how to: connect using dbName, dbHost
    // perform query, using provided connection:
    s"${conn.dbName}-${sql}-${conn.dbHost}" // <- Dummy implementation only here, so you can, for example, try it out in the REPL.
  }
}


class HasADbConnection(override val dbName: String,
                       override val dbHost: String) extends DbConnection {

  // You can create your actual connection here...
  val conn = makeConnection

  def doSomething(query: Query) = {
    // ... or here, according to your program's needs.
    val conn = makeConnection
    query.doQuery(conn)
  }

  def makeConnection = this // Not a real implementation, just a quick cheat for this example.
}

实际上,doQuery(可以更好地命名)应该具有DbConnection => ResultSet或类似的类型。用法示例:

scala> val hasConn = new HasADbConnection("myDb", "myHost")
hasConn: HasADbConnection = HasADbConnection@6c1e5d2f

scala> hasConn.doSomething(new Query("@"))
res2: String = myDb-@-myHost