Как установить обработчик бездействия для параметра по имени?
Я определил метод treeNode
создать узел, и который может иметь дочерние узлы. Упрощенный код:
def treeNode(text:String) (children: => Any) {
val b = new TreeNode(text)
children
}
Когда я использую этот метод, я должен написать:
treeNode("aaa") {
treeNode("bbb") {}
treeNode("ccc") {}
}
Вы можете видеть листовые узлы, у которых нет детей, но у них должен быть пустой блок {}
,
Есть ли способ дать параметр children: => Any
значение по умолчанию бездействия, что я могу написать код как:
treeNode("aaa") {
treeNode("bbb")
treeNode("ccc")
}
Помощь ~
2 ответа
Проблема не в том, что вы не можете присвоить ему значение бездействия (по умолчанию); проблема в том, что даже если вы это делаете, функции с несколькими блоками параметров должны иметь по крайней мере круглые скобки или скобки для каждого блока.
Есть одно исключение: на неявный блок параметров вообще не нужно ссылаться. К сожалению, вам не разрешено иметь неявные параметры по имени, и даже если бы вы были, ваша подпись позволила бы любому случайному неявному сработать в этом месте!
Теперь есть способ обойти это, который я покажу для полноты, но я предлагаю это (при условии, что вы не просто хотите другое имя, как leafNode
Вы просто оставляете след {}
там.
Вы можете получить именно тот синтаксис, который вам нужен, если вы выполните следующее. Во-первых, вам нужен неявный параметр, но вы делаете его классом-оболочкой (можно использовать Function0
который уже существует, но тогда следующий шаг может иметь непредвиденные последствия):
trait AnyByName { def eval: Any }
def treeNode(text: String)(implicit children: AnyByName) = (text,children.eval)
Теперь вам нужно две вещи - вы должны иметь возможность конвертировать по имени Any
в вашу новую черту, и вам нужно иметь неявный доступ ничего не делать. Итак, мы
implicit val nameForDoingNothing = new AnyByName { def eval = () }
implicit def wrap_any_by_name(a: => Any) = new AnyByName { def eval = a }
И теперь мы восстанавливаем поведение, за которым вы были:
scala> treeNode("Hi")
res1: (String, Any) = (Hi,())
scala> treeNode("Hi") { treeNode("there") }
res2: (String, Any) = (Hi,(there,()))
(в вашем примере вы ничего не возвращаете; здесь я делаю, чтобы показать, что это работает.)
Это много инструментов, чтобы избежать некоторых {}
Однако, именно поэтому я бы рекомендовал делать это только в том случае, если вы предполагаете, что это очень интенсивно используемый DSL и что два имени недопустимы. (Кроме того, если вы ожидаете, что он будет очень интенсивно использоваться, treeNode
вероятно болезненно длинна как имя; Я бы предложил просто node
.)
AFAICT вы не сможете пропустить своего рода пустой блок по умолчанию.
Кстати, вы могли бы просто разделить задачу на основе вашего treeNode
функция путем создания другого def leaf(text:String) = treeNode(t) {}