2016-12-30 18 views
0

このcommentの中で、@Benは、名前による呼び出しは、値がゼロ引数の関数である値による呼び出しと同等であることを提案しました。ゼロ引数の関数として解釈される値を持つ値による呼び出しと名前による呼び出し

私が正しく理解している場合、

def callByName(x: => Int) = { 
    // some code 
} 
callByName(something()) 

def callByValue(x:() => Int) = { 
    // same code as above, but all occurrences of x replaced with x() 
} 
callByValue(()=>something()) 

(::@MichaelZajac、@LukaJacobowitzで指摘したように、私は署名の誤りを修正し、もともと、それがcallByValue(x: Int)述べています。編集)に相当します

言い換えれば、 "名前で呼び出す"コンセプト全体は文法的な砂糖に過ぎません。「価値のある呼び出し」を使ってすべてのことが達成できます(いくつかの追加のキーストロークで)。真の場合は、名前による呼び出しを非常に理解しやすくなります。実際、私はこの技術をPythonで使っています(Pythonはファーストクラスの関数を持っています)。

さらに、commentsの下では、議論がやや複雑になり、それほど簡単ではないという気持ちが残っていました。

"名前で呼び出す"より重要なことがありますか?それとも、コンパイラによるゼロ引数関数の自動作成ですか?

答えて

1

あなたのcallByValue機能がIntの代わりに() => Intを取ることを意味していたと仮定しています。それ以外の場合はそれほど意味がありません。

あなたの考えはかなり正確です。コンパイラはFunction0インスタンスを生成します。 ScalaコードをJavapで逆コンパイルすると、これはきれいに見えます。

生成されたFunction0は、関数内でby-nameパラメータを使用するたびに再評価されるため、一度計算する必要がある場合は、次のようにします。

def callByName(x: => Int) = { 
    val a = x 
    // do something with a here 
} 

Hereは、全体的な考え方に関する情報です。 また、あなたはScalaはthis questionにかなりきちんと名前によるパラメータをコンパイルする方法を見ることができます:Javaで逆コンパイル

def getX[T <: X](constr: ⇒ T): Unit = { 
    constr 
} 

は同等です:

public <T extends X> void getX(Function0<T> constr) { 
    constr.apply(); 
} 
1

はい、しかし、あなたの例では、非常に適切ではありません。あなたの質問に書かれているcallByValueの署名は、callByValueが呼び出される前にxと評価されます。

以下は、コール・バイ・名前とほぼ同じになります:callByValueのバージョンが唯一Intのではなく、Int秒を返す関数を受け入れるため

def callByValue(x:() => Int) = { 
    // same code as above, but all occurrences of x replaced with x() 
} 

区別は、重要です。 xx()に置き換えた場合は、コンパイルできません。

ただし、call-by-nameのパラメータが=> Aの場合は、前者が使用するほうが簡単である点を除いて、() => Aとほぼ同じです。私はとおおよそと言っています。の異なるタイプであり、そのアプリケーションは少し異なります。 () => Aを種類として指定できますが、=> Aは指定できません。もちろん、x:() => Aを使用する場合は、xの代わりにx()を手動で呼び出す必要があります。

関連する問題