[SCALA] 동적 특성에 혼합
SCALA동적 특성에 혼합
형질을 갖는
trait Persisted {
def id: Long
}
어떻게 어떤 경우 클래스의 인스턴스를 받아 혼합 형질과의 복사본을 반환하는 방법을 구현합니까?
메소드의 서명은 다음과 같습니다
def toPersisted[T](instance: T, id: Long): T with Persisted
해결법
-
==============================
1.이은 (공식적으로 2.10.0-M3 이후 스칼라의 일부) 매크로를 수행 할 수 있습니다. 여기 당신을 위해 무엇을 찾고있는 요지의 예입니다.
이은 (공식적으로 2.10.0-M3 이후 스칼라의 일부) 매크로를 수행 할 수 있습니다. 여기 당신을 위해 무엇을 찾고있는 요지의 예입니다.
1) 내 매크로 제공된 경우 클래스와 지속 형에서 상속이 지속 된 훨씬 같은 새로운 T 할 것이라고 로컬 클래스를 생성합니다. 그런 다음, 그 인수 (복수 평가를 방지하기 위해)을 캐시하고 생성 된 클래스의 인스턴스를 생성한다.
2) 어떻게 어떤 나무를 생성하기 위해 알았 는가? 나는 AST를 인쇄하는 간단한 응용 프로그램, parse.exe가 해당 입력 코드를 구문 분석 결과. 난 그냥 구문 분석 클래스 인 $ Persisted1 호출 그래서 (첫째 : 문자열을, 마지막 : String)를 지속 형과 (이름, 성) 사람이 확장 출력을 언급 내 매크로에 재현. parse.exe는 scalac -Xprint에 대한 래퍼입니다 : 파서 -Yshow - 나무 -Ystop-후 : 파서. ,하는 AST를 찾아 "스칼라 2.10에서 메타 프로그래밍"에서 더 많은 읽을 수있는 다른 방법이 있습니다.
3) 매크로 확장은 scalac에 대한 인수로 -Ymacro 디버그 라이트를 제공하는 경우 확인 전성이 될 수 있습니다. 이 경우 모든 확장가 출력 될 것입니다, 당신은 빠른 CODEGEN 오류를 감지 할 수 있습니다.
편집하다. 2.10.0-M7 대한 예 업데이트
-
==============================
2.당신이 바닐라 스칼라를 사용하여 원하는 것을 달성 할 수 없습니다. 문제는이나 mixin은 다음과 같은 것입니다 :
당신이 바닐라 스칼라를 사용하여 원하는 것을 달성 할 수 없습니다. 문제는이나 mixin은 다음과 같은 것입니다 :
scala> class Foo defined class Foo scala> trait Bar defined trait Bar scala> val fooWithBar = new Foo with Bar fooWithBar: Foo with Bar = $anon$1@10ef717
바있는 푸 혼합 만들 수 있지만, 런타임에 수행되지 않습니다. 컴파일러는 단순히 새로운 익명 클래스를 생성합니다 :
scala> fooWithBar.getClass res3: java.lang.Class[_ <: Foo] = class $anon$1
것이 가능 - 스칼라에서 동적 믹스 인을 참조하십시오? 더 많은 정보를 위해서.
-
==============================
3.당신이 할하려는 것은 기록 연결, 스칼라의 타입 시스템이 지원하지 않는 무언가로 알려져있다. (FWIW는, 타입 시스템이 존재한다 - 등이이 같은 -.이 기능을 제공하는)
당신이 할하려는 것은 기록 연결, 스칼라의 타입 시스템이 지원하지 않는 무언가로 알려져있다. (FWIW는, 타입 시스템이 존재한다 - 등이이 같은 -.이 기능을 제공하는)
나는 형의 클래스가 사용 사례에 맞게 할 수 있다고 생각하지만, 문제는 당신이 해결하려고하는 어떤 문제에 대한 충분한 정보를 제공하지 않는 한 나는 확실히 말할 수 없다.
-
==============================
4.당신은 SORM 프로젝트의 일환으로 스칼라 2.10.0-RC1의 도구 상자의 API를 이용 날짜 작업 솔루션에 최대를 찾을 수 있습니다.
당신은 SORM 프로젝트의 일환으로 스칼라 2.10.0-RC1의 도구 상자의 API를 이용 날짜 작업 솔루션에 최대를 찾을 수 있습니다.
다음 용액 스칼라 2.10.0-M3 반사 API 및 스칼라 인터프리터에 기초한다. 동적으로 생성하고 혼합 형질 원래 케이스 클래스로부터 상속. 감사 캐시 클래스 최대 캐싱이 솔루션은 동적 각 오리지널 케이스 클래스에 대해 하나의 클래스를 작성하고 나중에 재사용한다.
새로운 반사 API가 많이 공개하는 것이 아니며이 안정적이며에는 튜토리얼이 없기 때문에 아직이 솔루션은 바보 repitative 행동과 단점을 포함 할 수있다.
다음 코드는 스칼라 2.10.0-M3 테스트되었습니다.
형질은 혼합한다. 내가 인해 내 프로그램의 업데이트에를 조금 변경 한 것을 바랍니다 참고
trait Persisted { def key: String }
실제 작업자 객체
import tools.nsc.interpreter.IMain import tools.nsc._ import reflect.mirror._ object PersistedEnabler { def toPersisted[T <: AnyRef](instance: T, key: String) (implicit instanceTag: TypeTag[T]): T with Persisted = { val args = { val valuesMap = propertyValuesMap(instance) key :: methodParams(constructors(instanceTag.tpe).head.typeSignature) .map(_.name.decoded.trim) .map(valuesMap(_)) } persistedClass(instanceTag) .getConstructors.head .newInstance(args.asInstanceOf[List[Object]]: _*) .asInstanceOf[T with Persisted] } private val persistedClassCache = collection.mutable.Map[TypeTag[_], Class[_]]() private def persistedClass[T](tag: TypeTag[T]): Class[T with Persisted] = { if (persistedClassCache.contains(tag)) persistedClassCache(tag).asInstanceOf[Class[T with Persisted]] else { val name = generateName() val code = { val sourceParams = methodParams(constructors(tag.tpe).head.typeSignature) val newParamsList = { def paramDeclaration(s: Symbol): String = s.name.decoded + ": " + s.typeSignature.toString "val key: String" :: sourceParams.map(paramDeclaration) mkString ", " } val sourceParamsList = sourceParams.map(_.name.decoded).mkString(", ") val copyMethodParamsList = sourceParams.map(s => s.name.decoded + ": " + s.typeSignature.toString + " = " + s.name.decoded).mkString(", ") val copyInstantiationParamsList = "key" :: sourceParams.map(_.name.decoded) mkString ", " """ class """ + name + """(""" + newParamsList + """) extends """ + tag.sym.fullName + """(""" + sourceParamsList + """) with """ + typeTag[Persisted].sym.fullName + """ { override def copy(""" + copyMethodParamsList + """) = new """ + name + """(""" + copyInstantiationParamsList + """) } """ } interpreter.compileString(code) val c = interpreter.classLoader.findClass(name) .asInstanceOf[Class[T with Persisted]] interpreter.reset() persistedClassCache(tag) = c c } } private lazy val interpreter = { val settings = new Settings() settings.usejavacp.value = true new IMain(settings, new NewLinePrintWriter(new ConsoleWriter, true)) } private var generateNameCounter = 0l private def generateName() = synchronized { generateNameCounter += 1 "PersistedAnonymous" + generateNameCounter.toString } // REFLECTION HELPERS private def propertyNames(t: Type) = t.members.filter(m => !m.isMethod && m.isTerm).map(_.name.decoded.trim) private def propertyValuesMap[T <: AnyRef](instance: T) = { val t = typeOfInstance(instance) propertyNames(t) .map(n => n -> invoke(instance, t.member(newTermName(n)))()) .toMap } private type MethodType = {def params: List[Symbol]; def resultType: Type} private def methodParams(t: Type): List[Symbol] = t.asInstanceOf[MethodType].params private def methodResultType(t: Type): Type = t.asInstanceOf[MethodType].resultType private def constructors(t: Type): Iterable[Symbol] = t.members.filter(_.kind == "constructor") private def fullyQualifiedName(s: Symbol): String = { def symbolsTree(s: Symbol): List[Symbol] = if (s.enclosingTopLevelClass != s) s :: symbolsTree(s.enclosingTopLevelClass) else if (s.enclosingPackageClass != s) s :: symbolsTree(s.enclosingPackageClass) else Nil symbolsTree(s) .reverseMap(_.name.decoded) .drop(1) .mkString(".") } }
테스트 응용 프로그램
import PersistedEnabler._ object Sandbox extends App { case class Artist(name: String, genres: Set[Genre]) case class Genre(name: String) val artist = Artist("Nirvana", Set(Genre("rock"), Genre("grunge"))) val persisted = toPersisted(artist, "some-key") assert(persisted.isInstanceOf[Persisted]) assert(persisted.isInstanceOf[Artist]) assert(persisted.key == "some-key") assert(persisted.name == "Nirvana") assert(persisted == artist) // an interesting and useful effect val copy = persisted.copy(name = "Puddle of Mudd") assert(copy.isInstanceOf[Persisted]) assert(copy.isInstanceOf[Artist]) // the only problem: compiler thinks that `copy` does not implement `Persisted`, so to access `key` we have to specify it manually: assert(copy.asInstanceOf[Artist with Persisted].key == "some-key") assert(copy.name == "Puddle of Mudd") assert(copy != persisted) }
-
==============================
5.그것의 생성 후 객체를 구성 할 수는 없지만 객체 타입 별칭과 정의 구조체를 사용하여 특정 조성물 여부를 결정하는 매우 넓은 테스트를 할 수 있습니다 :
그것의 생성 후 객체를 구성 할 수는 없지만 객체 타입 별칭과 정의 구조체를 사용하여 특정 조성물 여부를 결정하는 매우 넓은 테스트를 할 수 있습니다 :
type Persisted = { def id: Long } class Person { def id: Long = 5 def name = "dude" } def persist(obj: Persisted) = { obj.id } persist(new Person)
다음 DEF ID로 모든 개체 : 긴 지속 된 자격을 것입니다.
나는 당신이하려는 무슨 생각을 달성하는 것은 암시 적 변환 가능합니다 :
object Persistable { type Compatible = { def id: Long } implicit def obj2persistable(obj: Compatible) = new Persistable(obj) } class Persistable(val obj: Persistable.Compatible) { def persist() = println("Persisting: " + obj.id) } import Persistable.obj2persistable new Person().persist()
from https://stackoverflow.com/questions/10373318/mixing-in-a-trait-dynamically by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 케이스 클래스는 하나 개의 필드가있는 경우 경우 클래스에 JSON을 설정하는 방법 (0) | 2019.11.06 |
---|---|
[SCALA] 스칼라의 '::'연산자, 어떻게 작동합니까? (0) | 2019.11.06 |
[SCALA] 어떻게 자기 형을 구현하는 등 스칼라의이 입력, 추상적 인 유형을 사용 하는가? (0) | 2019.11.06 |
[SCALA] 어떻게 추가 "제공"종속성 / 테스트 작업 '클래스 경로를 실행하는 백업? (0) | 2019.11.06 |
[SCALA] 스칼라에서 유효한 식별자 문자 (0) | 2019.11.06 |