2017-01-06 3 views
4

В некотором методе я хотел бы заставить параметры называть. Причиной является автогенерированный код, для которого порядок параметров неуточнен (и останется таким образом).Можно ли использовать именованные параметры в scala?

Ближайший я могу получить это

private val _forceNamed: Object = new Object() 

def doSomething(forceNamed: Object = _forceNamed, arg1: String, arg2: String, ...): Unit = { 
    if (forceNamed != _forceNamed) { 
    throw Exception(something) 
    } 

    // actually do stuff 
} 

Однако это не удается только во время выполнения, в то время как что-то неисправного во время компиляции было бы гораздо лучше.

+1

Вы могли бы написать макрос каким-то образом. –

ответ

3

Если вы хотите, чтобы закрыть лазейку, чтобы быть в состоянии пройти в null, вам может использовать класс значений в качестве защитника.

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

class Foo { 
    import Foo._ 
    def foo(x: Bar = bar, a: String, b: String) = println(a + b) 
} 

object Foo { 
    private[Foo] class Bar(val i: Int) extends AnyVal 
    private val bar = new Bar(42) 
} 

// Exiting paste mode, now interpreting. 

defined class Foo 
defined object Foo 

scala> val f = new Foo 
f: Foo = [email protected] 

scala> f.foo(null, "", "") 
<console>:13: error: type mismatch; 
found : Null(null) 
required: Foo.Bar 
     f.foo(null, "", "") 
      ^
+0

Хороший ответ! Я не понимаю, почему вы можете сделать 'Bar'' 'private [Foo]', и это не считается экранирующей определяющей областью (ошибка, о которой сообщается, когда вы пытаетесь сделать 'Bar' как' private') , – Jamie

+1

@Jamie Хороший вопрос. Я не знаю ответа.Я подозреваю, что JVM будет отклонять файл класса, если закрывается частный класс. Но частный [Foo] должен быть скомпилирован для публики (или по умолчанию или защищен, я не уверен). Тогда JVM не знает, поэтому все равно. Не знаю, является ли это ошибкой или функцией скаляра. –

+2

https://issues.scala-lang.org/browse/SI-4323 –

1

Отличная идея.

Похоже, что проблемы гигиены с аргументами по умолчанию запрещают однотонные типы.

$ scala 
Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111). 
Type in expressions for evaluation. Or try :help. 

scala> private val x = new Object ; def f(foo: x.type = x, i: Int) = i 
<console>:11: error: private value x escapes its defining scope as part of type x.type 
     private val x = new Object ; def f(foo: x.type = x, i: Int) = i 
               ^

scala> val x = new Object ; def f(foo: x.type = (x: x.type), i: Int) = i 
x: Object = [email protected] 
f: (foo: x.type, i: Int)Int 

scala> f(i = 42) 
<console>:13: error: type mismatch; 
found : Object 
required: x.type 
     f(i = 42) 
    ^

или нет, это выглядит нормально:

private[this] val x: Object = new java.lang.Object(); 
    <stable> <accessor> def x: Object = $iw.this.x; 
    def f(foo: x.type = $iw.this.x, i: Int): Int = i; 
    <synthetic> def f$default$1: x.type = $iw.this.x 

или проблема присваивание значения по умолчанию?

но вы не можете сделать это:

scala> val x: x.type = new Object 
<console>:36: error: recursive value x needs type 
     val x: x.type = new Object 
      ^

Я предполагаю, что это работает, потому что вы не должны сказать ей, что x является x.type:

scala> object x 
defined object x 

scala> def f(y: x.type = x, i: Int) = i 
f: (y: x.type, i: Int)Int 

scala> f(i = 42) 
res2: Int = 42 

Это все еще позволяет явным образом обеспечивая x , которые могут быть запутаны.

Я слишком напуган, чтобы выяснить, почему это не удается:

scala> object x$$ ; def f(y: x$$.type = x$$, i: Int) = i 
defined object x$$ 
f: (y: .type, i: Int)Int 

scala> f(i = 42) 
res0: Int = 42 

scala> f(x$$, 42) // or x$$$ 
<console>:13: error: not found: value x$$ 
     f(x$$, 42) 
     ^

Но это говорит о том, что даже если объект является общедоступным, доступ к нему как-то парализованы имя коверкая.

+0

Похоже, хорошая идея, хотя и не зная, почему именно ваш последний пример терпит неудачу, кажется немного пугающим. – Jamie

2

Что-то вроде этого, может быть:

class Foo { 
    class Bar private[Foo]() 
    private val bar = new Bar 
    def foo(x: Bar= bar, a: String, b: String) = println(a + b) 
} 
+0

Может кто-нибудь еще сможет пройти null? Таким образом, все равно потребуется проверка времени выполнения. Хотя это имеет то преимущество, что у кого-то гораздо меньше шансов передать что-то случайно, что приведет к сбою во время выполнения, а не во время компиляции. – Jamie

2

Мы имеем это в нашей базе кода для этой цели:

object `(Please use explicitly named arguments)` 
def foo(
    `(Please use explicitly named arguments)`: 
    `(Please use explicitly named arguments)`.type = 
    `(Please use explicitly named arguments)`, 
    namedArg1: Int, 
    namedArg2: String, 
    ... 
) = ... 
+0

Не компилируется для меня, если имя параметра не совпадает с именем объекта. – jwvh

+0

Я считаю, что вы по-прежнему можете передать null для аргумента, который, конечно, кто-то не должен делать, но кто-то может это сделать – Jamie

0
Welcome to Scala 2.12.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102). 
Type in expressions for evaluation. Or try :help. 

scala> type `(Please use explicitly named arguments)` = Nothing 
defined type alias $u0028Please$u0020use$u0020explicitly$u0020named$u0020arguments$u0029 

scala> def foo(`(Please use explicitly named arguments)`: => `(Please use explicitly named arguments)` = ???, i: Int, j: Int) = i + j 
foo: ((Please use explicitly named arguments): => (Please use explicitly named arguments), i: Int, j: Int)Int 

scala> foo(null, 1, 4) 
<console>:13: error: type mismatch; 
found : Null(null) 
required: (Please use explicitly named arguments) 
    (which expands to) Nothing 
     foo(null, 1, 4) 
     ^

scala> foo(i = 1, j = 4) 
res1: Int = 5 
Смежные вопросы