gpt4 book ai didi

用于实例化 scala.slick.lifted.TableQuery 的 Scala 反射

转载 作者:行者123 更新时间:2023-12-02 02:32:40 25 4
gpt4 key购买 nike

我有这个基本特征

trait MyBase {
type M
type T <: Table[M]
val query: TableQuery[T]
}

其中TableQueryscala.slick.lifted.TableQuery

我的子类实例化TableQuery,如下所示:

type M = Account
type T = AccountsTable
val query = TableQuery[T]

我想在基本特征中实例化TableQuery,可能通过使用lazy val,即

lazy val query: TableQuery[T] = {
...
}

我一直在尝试反射(reflection),但运气不佳。

最佳答案

如果我理解正确的话,你想要的是能够扩展MyBase 只需定义 MT,但无需在每个派生类中显式实例化 TableQuery

使用反射并不是真正的选择,因为通常您使用TableQuery.apply为此(如 val query = TableQuery[MyTable]),这是通过宏实现的,所以你遇到了“运行时与编译时”问题。

如果您绝对需要 MyBase 成为一个特征(而不是一个类),那么我看不到任何可行的解决方案。但是,如果您可以将 MyBase 转换为类MT 转换为类型参数(而不是抽象类型) ),那么至少有一个解。正如我在另一个相关问题( How to define generic type in Scala? )中暗示的那样,您可以定义一个类型类(例如 TableQueryBuilder)来捕获对 TableQuery.apply 的调用(在具体类型已知的情况下)以及隐式宏(例如 >TableQueryBuilder.builderForTable) 提供该类型类的一个实例。然后,您可以定义一个方法(例如 TableQueryBuilder.build)来实际实例化 TableQuery,它将仅将作业委托(delegate)给类型类。

// NOTE: tested with scala 2.11.0 & slick 3.0.0
import scala.reflect.macros.Context
import scala.language.experimental.macros
object TableQueryBuilderMacro {
def createBuilderImpl[T<:AbstractTable[_]:c.WeakTypeTag](c: Context) = {
import c.universe._
val T = weakTypeOf[T]
q"""new TableQueryBuilder[$T]{
def apply(): TableQuery[$T] = {
TableQuery[$T]
}
}"""
}
}
trait TableQueryBuilder[T<:AbstractTable[_]] {
def apply(): TableQuery[T]
}
object TableQueryBuilder {
implicit def builderForTable[T<:AbstractTable[_]]: TableQueryBuilder[T] = macro TableQueryBuilderMacro.createBuilderImpl[T]
def build[T<:AbstractTable[_]:TableQueryBuilder](): TableQuery[T] = implicitly[TableQueryBuilder[T]].apply()
}

最终效果是您不再需要知道类型 T 的具体值就能够实例化 TableQuery[T],前提是您在范围内有一个 TableQueryBuilder[T] 的隐式实例。换句话说,您可以转移了解 T 具体值的需要直到您真正了解为止。

MyBase (现在是一个类)可以像这样实现:

class MyBase[M, T <: Table[M] : TableQueryBuilder] {
lazy val query: TableQuery[T] = TableQueryBuilder.build[T]
}

然后您可以扩展它,而无需显式调用 TableQuery.apply:

class Coffees(tag: Tag) extends Table[(String, Double)](tag, "COFFEES") {
def name = column[String]("COF_NAME")
def price = column[Double]("PRICE")
def * = (name, price)
}

class Derived extends MyBase[(String, Double), Coffees] // That's it!

这里发生的情况是,在 Derived 的构造函数中,TableQueryBuilder[Coffees] 的隐式值是隐式的传递给 MyBase 的构造函数。

如果 MyBase 是一个特征,则不能应用此模式的原因很平常:特征构造函数不能有参数,更不用说隐式参数了,因此不会有隐式方法传递 TableQueryBuilder 实例。

关于用于实例化 scala.slick.lifted.TableQuery 的 Scala 反射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30183000/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com