#scala #path #scala.js #scala-macros #scala-reflect
#scala #path #scala.js #scala-макросы #scala-reflect
Вопрос:
Предположим, что вы хотите перемещаться по графу объектов навигационным способом, аналогичным тому, как мы перемещаемся по файловым системам.
Например, представьте, что у вас есть граф объектов, который поддерживает это выражение:
var x = objName.foo.bar.baz.fieldName
Мы можем закодировать это выражение доступа к данным как path следующим образом:
"objName/foo/bar/baz/fieldName"
Разбивая этот путь на сегменты, мы можем легко перемещаться по графу объектов в JavaScript, потому что в дополнение к традиционной точечной нотации он также поддерживает нотацию доступа к массиву: objName["foo"]["bar"]["baz"]["fieldName"]
.
В Java или JVM Scala мы можем использовать отражение для перемещения по графам объектов, но как бы вы следовали этим типам путей для перемещения по графам объектов Scala в Scala.js среда?
Другими словами, учитывая путь, похожий по форме на URI, как бы вы прошли по Scala.js объекты и поля?
Комментарии:
1. Объекты, определенные в Scala, или объекты, определенные в JS? Я думаю, что в настоящее время вы получаете разные ответы, в зависимости. (Хотя я думаю, что в Scala 3 это может работать одинаково в любом случае.) Честно говоря, я не уверен, как это сделать для обычных объектов Scala в Scala.js окружающая среда…
2. Привет, Джастин. Речь идет об обычных объектах Scala в Scala.js среда, но если она не может работать для объектов scala в целом, можете ли вы придумать способ разработки классов Scala с учетом этой возможности?
Ответ №1:
Вы, конечно, могли бы использовать макрос для преобразования постоянного String
представления в средство доступа во время компиляции, но я предполагаю, что вы хотите иметь возможность делать это во время выполнения для произвольных строк.
Если цель состоит в том, чтобы иметь возможность обходить частично построенные пути, то это всего лишь вопрос передачи функций доступа. Вы могли бы использовать что-то подобное, чтобы сделать его красивее:
class Path[ A](private val value: () => A) {
def resolve: A = value()
def /[B](f: A => B): Path[B] = new Path(() => f(resolve))
}
implicit class PathSyntax[A](val a: A) extends AnyVal {
def /[B](f: A => B): Path[B] = new Path(() => a) / f
}
object Foo {
val bar = Bar
}
object Bar {
val baz = Baz
}
object Baz
Синтаксис не совсем такой красивый, но теперь он безопасен для ввода и выглядит не так уж плохо:
val barPath: Path[Bar.type] = Foo / (_.bar)
val bazPath: Path[Baz.type] = barPath / (_.baz)
Против этого потребовалось бы больше работы, например. между ними нет надлежащего равенства / сравнения Paths
.
Если вы хотите придерживаться своего подхода, я не знаю прямого решения. Однако я бы сказал, что весь смысл использования ScalaJS заключается в сохранении строгих типов и избежании любого шаблона, который мог бы привести к ошибкам во время выполнения, которые компилятор мог бы предотвратить, если бы вы позволили ему выполнять свою работу.