我是scala的新手,无法理解Lift家伙如何实现Record API。但是,关于此API的问题较少,但更多关于Scala的问题。我对类模式中的对象如何工作感兴趣,在Lift中使用。
class MainDoc private() extends MongoRecord[MainDoc] with ObjectIdPk[MainDoc] {
def meta = MainDoc
object name extends StringField(this, 12)
object cnt extends IntField(this)
}
object MainDoc extends MainDoc with MongoMetaRecord[MainDoc]
在上面的代码段中,您可以看到如何在Lift中定义记录。有趣的是,字段被定义为对象。 API允许您创建如下实例:
val md1 = MainDoc.createRecord
.name("md1")
.cnt(5)
.save
这可能是通过使用apply方法完成的?但与此同时,您可以通过执行以下操作来获取值:
val name = md1.name
这一切如何运作?在类的范围内,对象不是静态的。或者它们只是一些内部表示的构造函数类?如何迭代所有字段,你使用Reflection?
谢谢, 奥托
答案 0 :(得分:3)
奥托,
你在正确的轨道上更少。实际上,您不需要将字段定义为对象,您可以将示例编写为
class MainDoc private() extends MongoRecord[MainDoc] with ObjectIdPk[MainDoc] {
def meta = MainDoc
val name = new StringField(this, 12)
val cnt= new IntField(this)
}
object MainDoc extends MainDoc with MongoMetaRecord[MainDoc]
net.liftweb.record.Field trait确实包含一个与set等效的apply方法。这就是为什么你可以在实例化对象后按名称分配字段。
您提到的字段参考:
val name = md1.name
将类型名称键入StringField。如果你在想什么
val name: String = md1.name
将无法编译(除非在范围内隐含转换Field [T] => T)。检索字段的String值的正确方法是
val name = md1.name.get
记录确实使用反射来收集字段。在类中定义对象时,编译器将创建一个字段来保存对象实例。从反射的角度来看,该对象看起来非常类似于我之前提到的定义字段的替代方式。每个定义可能会创建字段类型的子类,但这与
没有区别val name = new StringField(this, 12) {
override def label: NodeSeq = <span>My String Field</span>
}
答案 1 :(得分:1)
你认为它是apply
方法是正确的。记录的Field
base class定义了一些apply
方法。
def apply(in: Box[MyType]): OwnerType
def apply(in: MyType): OwnerType
通过返回OwnerType
,您可以将调用链接在一起。
关于使用object
来定义字段,一开始也让我很困惑。 object
标识符定义特定范围内的对象。尽管将object
视为singleton pattern的快捷方式很方便,但它比这更灵活。根据{{3}}(第5.4节):
它大致等同于以下懒惰值的定义:
lazy val m = new sc with mt1 with ... with mtn { this: m.type => stats }
&LT;剪断/&GT;
上面给出的扩展对于顶级对象不准确。它不可能是因为变量和方法定义不能出现在a的顶层 包对象(第9.3节)。相反,顶级对象被转换为静态字段。
关于迭代所有字段,Record
个对象定义了allFields
方法,该方法返回List[net.liftweb.record.Field[_, MyType]]
。