2016-09-10 8 views
1

現在、私はスカラコードベースを別々の地理的位置にまたがって管理しています。もの。私の最初の手の理解が私の当面の目標は、今、その層に浸透し、基本的なビルディングブロックされているかを確認することですので、Scalaは、シンタックスシュガーコードのかなり厚い層を持っているということでした。スカラの関数定義がどのように特性に評価されるのかを理解する

私はいくつかのドキュメントを読んだ後、Scalaではすべての関数定義は基本的に満たされた「適用」方式と特性であることを理解したよう。(匿名ボディ/ Javaでクラスとのインタフェースに類似)。これを基本として設定してください(私の基本的な理解自体が間違っていれば私を修正してください)、私はScalaで関数定義を使いこなしています。

def func (s:String):Int = { 
    100 
    } 

new Function1[String, Int] { 
    def apply(s:String):Int = { 
     100 
    } 
    } 

に評価しかし、どのような(そしてどのようにする)は、次の特性の定義に評価されない:

はこの考えてみましょうか?

def func (body: => Boolean):Int = { 
    body; 
    100; 
} 

この場合、「新しい機能...」コードはどのように見えるのですか?混乱の場合

答えて

3

は、javap出力に見えます。 ScalaのREPLはそれを確認するための便利な方法を提供します:

scala> def func (body: => Boolean):Int = { 
    |  body; 
    |  100; 
    | } 
func: (body: => Boolean)Int 

scala> :javap -c func 
Compiled from "<console>" 
public class { 
    public static final MODULE$; 

    public static {}; 
    Code: 
     0: new   #2     // class 
     3: invokespecial #12     // Method "<init>":()V 
     6: return 

    public int func(scala.Function0<java.lang.Object>); 
    Code: 
     0: aload_1 
     1: invokeinterface #20, 1   // InterfaceMethod scala/Function0.apply$mcZ$sp:()Z 
     6: pop 
     7: bipush  100 
     9: ireturn 

    public(); 
    Code: 
     0: aload_0 
     1: invokespecial #24     // Method java/lang/Object."<init>":()V 
     4: aload_0 
     5: putstatic  #26     // Field MODULE$:L; 
     8: return 
} 

だからここにあなたがbody: => Booleanがバイトコードでscala.Function0<java.lang.Object>として表現されていることがわかります。

私はここscala 2.11.8バージョンを使用しています。 Scala 2.12は、可能な限りデフォルトメソッド(インターフェース)やSAMsのようなjava8の機能を再利用しようとします(2.11のintropを有効にする-Xexperimentalフラグを試すことができます)。それは別のバイトコード(Javaと互換性がありません< 8)とより良いパフォーマンスにつながります。あなたはより多くについて2.12hereを変更を読み取ることができます。

+0

感謝ダイブ!それは洞察力があった。それでは、 "新しいFunction ....."コードはどのように見えるでしょうか? – soupybionics

+0

@soupybionics '' 'val body = newのようなものです。Function0 [Boolean] {def apply():Boolean = println(" calling body "); true} '' '、' 'func'の' 'Function1''と同様です。 ':=>'の構文(名前による呼び出しとも呼ばれる)はそれ以上のものではなく、 '' argsをとり何かを返す ''関数であることに注意してください。 – dveim

+0

バイトコードを見るだけでは、型に何が起こるかは実際には分かりません。あなたは 'Function0'でそれを定義することはできません、それは別のタイプを持っています。 –

0

Dviemのコメントの助けを借りて、コードは次のようになります。すべての

def func (s:String):Int = { 
    100 
} 

val func = new Function1[()=>Boolean, Int] { 
      def apply(fn:()=>Boolean):Int = { fn(); 100 } 
      } 

>>> func: (() => Boolean) => Int = <function1> 

func (new Function0[Boolean] { 
     def apply():Boolean = { println ("returning true"); true } 
     }) 

>>> returning true 
>>> res0: Int = 100 
1

まず関数ではありません、それは方法ですが、それには値がありませんし、 を単独で評価していません。あなたは(関数にメソッドを変換するためのScalaの用語をイータ展開したいのであれば

new Function1[String, Int] { 
    def apply(s:String):Int = { 
    func(s) 
    } 
} 

:機能的な状況に置かれたとき、それは機能するのではなく、別のもの(Scalaはラッパーを作成します)に展開されてい)

def func (body: => Boolean):Int = { 
    body; 
    100; 
} 

それは次のようになります。

new Function1[=> Boolean, Int] { 
    def apply(body: => Boolean):Int = { 
    func(body) 
    } 
} 

とScalaはのように入力例を示します

(=> Boolean) => Int 

しかし、ここで問題となるのは、by-name型を型パラメータとして使用できないため、Function1 traitを使用してこの関数を定義する正当な方法がないように見えます。ラムダ構文を使用して、回避策が(で、名前はそこに許可されていない、けれども私は明示的にbodyの型を宣言することはできません)があるよう

が見える

UPDATE:

var expandedFunc: (=> Boolean) => Int = body => func(body) 
関連する問題