2012-06-05 4 views
0

저는 scala에 익숙하지 않아서 Lift 녀석들이 어떻게 Record API를 구현했는지에 대해 머리 숙여 질 수 없습니다. 그러나이 API에 대한 질문은 적지 만 스칼라에 대한 자세한 내용은 일반적으로 다릅니다. 클래스 패턴의 오브젝트가 Lift에서 사용되는 방식에 관심이 있습니다.Lift Framework에서 사용되는 클래스 패턴의 객체는 어떻게 작동합니까?

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] 

상단 스 니펫에서 리프트에 레코드가 정의되는 방식을 볼 수 있습니다. 흥미로운 부분은 필드가 객체로 정의된다는 것입니다. API를 사용하면 다음과 같은 인스턴스를 만들 수 있습니다.

val md1 = MainDoc.createRecord 
    .name("md1") 
    .cnt(5) 
    .save 

이것은 아마도 적용 방법을 사용하여 수행 할 수 있습니까? 그러나 동시에 다음과 같은 방법으로 값을 얻을 수 있습니다.

val name = md1.name 

이 모든 기능은 어떻게 작동합니까? 클래스의 범위 내에있을 때 객체가 정적이지 않은가? 아니면 내부 표현을위한 생성자 클래스입니까? 모든 필드를 반복하는 것이 어떻게 가능합니까? Reflection을 사용합니까?

덕분에, 오토

답변

1

당신은 그것이 apply 방법 것에 대해 말이 맞아. 레코드의 Field base class은 몇 가지 apply 방법을 정의합니다.

def apply(in: Box[MyType]): OwnerType 
def apply(in: MyType): OwnerType 

OwnerType을 반환하면 호출을 함께 연결할 수 있습니다.

필드를 정의하기 위해 object을 사용하는 것에 관해서는 혼란 스러웠습니다. object 식별자는 특정 범위 내의 개체를 정의합니다. objectsingleton pattern의 바로 가기로 생각하는 것이 편리하지만 더 유연합니다. Scala Language Spec (섹션 5.4)에 따르면
lazy val m = new sc with mt1 with ... with mtn { this: m.type => stats }

< 한조각 />

팽창 주어진 :

그것은 지연 값을 다음의 정의상 대략 동등 위의 내용은 최상위 수준 개체에 대해서는 정확하지 않습니다. 변수 및 메소드 정의가 패키지 객체 (§9.3) 외부의 최상위 레벨에 나타나지 않기 때문에 그럴 수 없습니다. 대신 최상위 수준의 개체는 정적 필드로 변환됩니다.

모든 필드의 반복에 대해서, Record 객체는 반환 List[net.liftweb.record.Field[_, MyType]]allFields 방법을 정의한다.

3

오토,

당신은 올바른 길을 가고 있습니다. 당신은 실제로 당신은 net.liftweb.record.Field의 특성을 설정하는 해당 인 적용 방법을 포함 않습니다

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] 

로 예를 쓴 수, 객체로 필드를 정의 할 필요가 없습니다. 그래서 개체를 인스턴스화 한 후에 필드를 이름으로 지정할 수 있습니다.

필드 참조 당신이 언급 한 :

val name = md1.name 

가 StringField로 이름을 입력합니다. 만약 당신이 생각하고있는 것이 있다면 (Field [T] => T로 변환하는 암시 적 범위가 없다면) 컴파일에 실패한

입니다. 필드의 문자열 값을 검색하는 올바른 방법은

val name = md1.name.get 

레코드가 필드를 수집하는 데 사용됩니다. 클래스 내에 오브젝트를 정의하면 컴파일러는 오브젝트 인스턴스를 보유 할 필드를 작성합니다. 반사의 관점에서 볼 때, 객체는 앞에서 언급 한 필드를 정의하는 대체 방법과 매우 유사합니다. 각 정의는 아마도 필드 유형의 서브 클래스를 생성하지만, 이는

과 다를 바 없습니다.