2017-01-06 6 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

を、あなたにガードとして値クラスを使用できます。

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''にすることができ、 '' Bar''を '' private''にしようとしたときに報告されるエラーです。 。 – Jamie

+1

@Jamie良い質問です。私は答えを知らない。プライベートクラスが漏洩した場合、JVMがクラスファイルを拒否すると思われます。しかし私的な[Foo]はpublicにコンパイルされなければなりません(あるいはデフォルトまたは保護されています、わかりません)。それから、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) 
    ^

あるいは全く、これは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 

かの問題がデフォルト値に割り当てているのですか?

が、あなたはこれを行うことはできません。まだ明示的xを提供することができます

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 

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$$ ; 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

誰かがまだヌルを渡すことはできますか?だから、それはまだランタイムチェックが必要です。これには利点がありますが、コンパイル時の代わりに実行時に障害が発生する可能性があります。 – Jamie

2

私たちは、この目的のために私たちのコードベースでのこの持っている:あなたはnullに合格することができるという抜け穴を閉じたい場合は

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 
関連する問題