2013-10-26 5 views
8

で関数を定義するための:DEFまたはVal、私は私の大学でプログラミングパラダイムを学習し、機能をこのように定義された講師により提供されるこのコース材料読んでいるScalaの

val double = (x: Int) => 2 * x 
double: Int => Int = <function1> 

しかし、私自身の研究からは私が見つけました

def d (x: Int) = 2 * x 
d: (x: Int)Int 

私はScalaを使い慣れていません。そして、両方の定義は次の結果を与える:

res21: Int = 8 

4をパラメータとして渡すと、 今私の主な質問は、なぜ講師はvalを使って関数を定義するのですか? valを使用しないと、私が知らないいくつかの利点が追加されます。私は、valを使って、プログラムの後半でプレースホルダをいくつかの名前にすることを理解していますが、私は間違ってval double = 5と書くことができました。 この段階では、誰かが別の方法で教えない限り、私は関数を定義するより良い方法を学んだと確信しています。

+0

私はScalaについて何かを述べる資格はありませんが、関数が 'double'として定義された後、実際に' val double = 5'を実行しようとしましたか?一度名前が定義されると、それを再定義することは不可能でなければならないという印象を受けました。いずれにしても、valとdefの両方で同じ結果が得られます。違いは単なる文体です。多くの場合、 'def'を使って関数を定義する方がはっきりしますが、' val'で定義するのが理にかなっています。あなたが不明な場合は、混乱を招く可能性が低いので、 'def'を使うことをお勧めします。 – kqr

+0

はい、私は 'double double 'とタイプし、' res24:Int = 5'を得ました – Emanuel

+0

[Scalaのメソッドと関数の違い](http://stackoverflow.com/questions/2529184) /メソッド間の違いとスカラ関数) –

答えて

12

厳密に言えば、def d (x: Int) = 2 * xは関数ではなくメソッドですが、scalaはメソッドを透過的に関数に変換できます。つまり、Int => Int機能が必要な場所でdメソッドを使用できます。

新しい変換インスタンスが毎回作成されるため、この変換を実行するためのオーバーヘッドはわずかです。私たちのプログラムは、単一の関数を作成し、それを再利用し、明示的valを使用して関数を定義するときに

1477986427 
1477986427 
574533740 
1102091268 

あなたが見ることができますので、同様に出力になり

val double = (x: Int) => 2 * x 
def d (x: Int) = 2 * x 

def printFunc(f: Int => Int) = println(f.hashCode()) 

printFunc(double) 
printFunc(double) 
printFunc(d) 
printFunc(d) 

は:私たちは、これがここで起こって見ることができますprintFuncへの引数として渡すと(同じハッシュコードが表示されます) defを使用すると、関数への変換は毎回printFuncに渡され、さまざまなハッシュコードを持つ関数のインスタンスがいくつか作成されます。 Try it

つまり、パフォーマンスのオーバーヘッドは小さく、しばしば私たちのプログラムに実質的な違いはありません。だから、多くの人がより簡潔で読みやすいと感じるように、defがよく定義されています。

+2

[一部の男](http://japgolly.blogspot.com.au/2013/10/scala-methods-vs-functions.html)はちょうど最近、ベンチマークを実行し、 "η拡張"を示しています引数として渡すときの関数)は、実際にはパフォーマンス上の不利益を被りません。 –

+0

いい投稿です。私もガベージコレクションの増加があるかもしれないと思うが、私はそれが小さい/存在しないことも想像する。 – theon

0

次のようなものが存在することがあるので:だから、その目的は、非常に単純な例で明らかではないかもしれません

abstract class BaseClass { 
    val intToIntFunc: Int => Int 
} 

class A extends BaseClass { 
    override val intToIntFunc = (i: Int) => i * 2 
} 

を。しかし、そのFunction値は高階関数に渡すことができます:関数をパラメータとしてとる関数。 Scalaのコレクションのドキュメントを見ると、関数をパラメータとして取る多数のメソッドが見られます。その非常に強力で汎用性の高いツールですが、コスト/メリットが明らかになる前に、アルゴリズムにある複雑さと親しみを持たせる必要があります。

また、識別子名として「double」を使用しないことをお勧めします。法的なScalaでも、Double型と混同するのは簡単です。

5

スカラでは、関数値は単相性です(つまり、型パラメータ、別名「ジェネリックス」を持つことはできません)。あなたはポリモーフィック機能が必要な場合は、メソッドを使用してそれを定義することによって、たとえば、この問題を回避する必要があります。

def headOption[A]: List[A] => Option[A] = { 
    case Nil => None 
    case x::xs => Some(x) 
} 

val headOption[A]を書くための有効な構文ではありません。これは多相関数値を作成していないことに注意してください。単なる多態的な方法であり、適切な型の単態関数値を返します。

+0

+1これは意識している重要な違いです – theon

関連する問題