Как установить обработчик ничего не делать для параметра по имени? - PullRequest
4 голосов
/ 08 января 2012

Я определил метод 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 ]

9 голосов
/ 08 января 2012

Проблема в , а не в том, что вы не можете присвоить ему значение бездействия (по умолчанию); проблема в том, что даже если вы это сделаете, функции с несколькими блоками параметров должны иметь минимум иметь круглые скобки или фигурные скобки для каждого блока.

Существует одно исключение: на блок параметров неявный вообще не нужно ссылаться. К сожалению, вам не разрешено иметь неявные параметры по имени, и даже если бы вы были, ваша подпись позволила бы любому случайному неявному сработать в этом месте!

Теперь, есть способ обойти это, который я покажу для полноты, но я предлагаю, что (при условии, что вам не нужно просто другое имя, например 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.)

6 голосов
/ 08 января 2012

AFAICT вы не сможете пропустить своего рода пустой блок по умолчанию.

Кстати, вы могли бы просто разделить задачу на основе вашей функции treeNode, создав другую def leaf(text:String) = treeNode(t) {}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...