2017-01-06 38 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不知道,所以它不在乎。不知道這是一個scalac錯誤還是功能。 –

+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) 
    ^

或沒有,這看起來OK:

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) 
     ^

但是,這表明,即使對象是公共的,對它的訪問是通過某種方式名字改編削弱。

+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 
相關問題