Хранение длинных сопоставителей квазикотировок в переменной

Я стараюсь избегать повторения длинных квазикавычек в матчах. Итак, я хотел бы преобразовать это:

def appendTree(clazz: ClassDef, tree: Tree): ClassDef =
  clazz match {
    case q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }" =>
      q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats; ..$tree }"
  }

к чему-то вроде этого:

val clazzQuote = "$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }"

def appendTree(clazz: ClassDef, tree: Tree): ClassDef =
  clazz match {
    case q"$clazzQuote" =>
      q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats; ..$tree }"
  }

Сравнимый пример того, что я пытаюсь сделать с интерполяцией строк:

val msg = "hello $name"

"hello world" match {
  case s"$msg" => println(name) // I want this to output "world"
}

Этот пример также не работает.

Как я могу это сделать? (или можно?)


person ofo    schedule 11.09.2020    source источник


Ответы (1)


Вы не можете писать

val msg = s"hello $name" // name doesn't make sense here

or

val clazzQuote = "$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }"
// mods, tpname, tparams, ... do not make sense here

В Scala сопоставление с образцом работает иначе.

Вы можете написать либо

clazz match {
  case q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }" =>
    q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats; $tree }"
}

or

clazz match {
  case ClassDef(mods, name, tparams, Template(parents, self, body)) =>
    ClassDef(mods, name, tparams, Template(parents, self, body :+ tree))
}

or

clazz match {
  case c: ClassDef =>
    val i = c.impl
    ClassDef(c.mods, c.name, c.tparams, Template(i.parents, i.self, i.body :+ tree))
}

Если вам нужны не все параметры, вы можете использовать символы подчеркивания

clazz match {
  case q"$_ class $tpname[..$_] $_(...$_) extends $_" =>
    println(tpname)
}

or

clazz match {
  case q"$_ class $_[..$_] $_(...$_) extends { ..$_ } with ..$parents { $_ => ..$_ }" =>
    println(parents)
}

В сложных случаях вы можете использовать пользовательские объекты экстрактора.

Если вы часто добавляете дерево в тело класса, вы можете ввести вспомогательный метод

def modifyBody(clazz: ClassDef, f: List[Tree] => List[Tree]): ClassDef =
  clazz match {
    case q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }" =>
      q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..${f(stats)} }"
  }

def appendTree(clazz: ClassDef, tree: Tree): ClassDef = {
  clazz match {
    case c => modifyBody(c, stats => stats :+ tree)
}
person Dmytro Mitin    schedule 11.09.2020
comment
Хм, похоже, мне лучше обойтись без квазицитата, так как без него он выглядит менее загроможденным. Это действительно отличный ответ. Спасибо! - person ofo; 11.09.2020