是否可以在scala中强制命名参数?

时间:2017-01-06 20:08:58

标签: 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
}

然而,这只会在运行时失败,而在编译时失败的东西会更好。

5 个答案:

答案 0 :(得分: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 = Foo@4a4f9c58

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

答案 1 :(得分:2)

这样的事情可能是:

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

答案 2 :(得分: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,
  ...
) = ...

答案 3 :(得分:1)

多么好主意。

看起来默认args的卫生问题禁止单身类型。

$ 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 = java.lang.Object@1e54cb33
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
              ^

我想这很有效,因为你不必告诉它xx.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)
         ^

但这表明即使对象是公开的,对它的访问也会因名称损坏而瘫痪。

答案 4 :(得分: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