1

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

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("")
  }
}

有没有办法避免在 new Query() 创建中出现多余的“override val dbName = self.dbName, override val dbHost = self.dbHost”,而是指示新的 Query 对象应该继承自/委托给 HasADbConnection 实例对于这些领域?

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

4

1 回答 1

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
于 2013-09-20T13:47:10.550 回答