Scala макросы. Как создать экземпляр подкласса и динамически смешать черту
Мотивация:
(не тесно связана с этой темой, но излагает вариант использования. Skippable)
я использую Scala.js
написать код React. Теперь у меня есть form
который содержит кучу input
с, каждый нуждается в onChange callback
в его опорах. См. Контролируемый компонент.
case class Input(info:String,value:String,onChange:(e:Event)=>Unit)
Проблема в: info
который не имеет ничего общего с React
, но был связан с этим. Я бы отделил логику управления от веб-содержимого. Так я и сделал:
trait Control[T]{val value:T,val onChange:(e:Event)=>Unit}
case class Input(info:String)
//when need to create a controlled props:
private trait TextInputCtrl extends Control[String]{//..implementation}
new Input("some info") with TextInputCtrl
Это решило только половину проблемы связи. Потому что реализация TextInputCtrl
должен быть написан внутри компонента React для доступа к состоянию. Так же new Input(...)
, если не сделать TextInputCtrl
общественности. Но если вы делаете, вы несете логику React снаружи.
Что ж. Если черта может быть динамически смешана с экземпляром. Я мог бы создать неконтролируемый чистый Input
экземпляр где-нибудь еще, и передать его в компонент React. Гораздо более гибкий. Это даже обеспечивает такие рычаги, как:
Seq(input...).map(_ with XXControl)
Итак, я попытался:
Вопрос:
Я хотел использовать эту простую философию:
def dynamix(in:Input):Input with Control{
new Input(in.info) with Control{//..implementation}
}
но через макросы:
q"""
new $MixinToolSym[$tpeC,$tpeT]{
def dynamix(in: $tpeC): $tpeC with $tpeT = {
new $tpeC (..$constrBody) with $tpeT
}
}
"""
Я достиг успешной компиляции. Но не удалось во время выполнения:
trait MixinTool[C, T] {
def dynamix(in: C): C with T
}
object MixinTool {
implicit def materialize[C, T]: MixinTool[C, T] = macro MacroImpl.impl[C, T]
}
val mt=MixinTool.materialize[Input,Control]
mt.dynamix(inputInstance) //error
Это бросает:
java.lang.IllegalAccessError:
tried to access field x.x.Input.info from class x.x.X$$anon$3$$anon$2
В чем проблема?
Это не проблема о scala App
,
================================================== знак равно
Обсуждение других способов достижения разъединяющей цели:
Другие подходы: (но, вероятно, не лучшие решения)
Ниже оба теряют способность черт самопознания напрямую обращаться к другим полям. И трудно последовательно или частично переопределить логику управления.
case class PropsContainer(input:Input,control:Control = Control.empty)
или же:
case class Input(info:String,value:String="",onChange: Control = Control.empty)
def addControl(input:Input,control:Control):Input{
input.copy(onChange = control)
}