Spark回炉再構築のScalaプログラミング詳細~関数入門

4593 ワード

目次
関数の開始
関数の定義と呼び出し
複数行文の関数体
再帰関数と戻りタイプ
既定のパラメータ
JavaとScalaはデフォルトのパラメータの違いを実現します
バンド名パラメータ
のびパラメータ
シーケンス呼び出しの長さパラメータの使用
かんすうてつづき
Lazy値
異常
小結
関数の開始
関数の定義と呼び出し
Scalaで関数を定義する場合は、関数の関数名、パラメータ、関数体を定義する必要があります.
最初の関数は次のとおりです.
def sayHello(name: String, age: Int) = {
  if (age > 18) { printf("hi %s, you are a big boy
", name); age }    else { printf("hi %s, you are a little boy
", name); age  } sayHello("leo", 30)

Scalaはすべてのパラメータのタイプを指定する必要がありますが、必ずしも関数の戻り値のタイプを指定する必要はありません.右側の関数体に再帰的な文が含まれていない限り、Scalaは自分で右側の式に基づいて戻りタイプを推定することができます.
複数行文の関数体
1行の関数:
def sayHello(name: String) = print("Hello, " + name)

関数ボディに複数行のコードがある場合は、コードブロックを使用して複数行のコードを包むことができます.コードブロックの最後の行の戻り値は、関数全体の戻り値です.Javaとは異なり、returnを使用して値を返すわけではありません.
たとえば、次のような関数を使用して、累積機能を実現します.
def sum(n: Int) = {
  var sum = 0;
  for(i 

再帰関数と戻りタイプ
関数自体を関数内で再帰的に呼び出す場合は、関数の戻りタイプを手動で指定する必要があります.
例えば、古典的なフィボナッチ数列を実現する:9+8;8 + 7 + 7 + 6; 7 + 6 + 6 + 5 + 6 + 5 + 5 + 4; ....
def fab(n: Int): Int = {
  if(n <= 1) 1
  else fab(n - 1) + fab(n - 2)
}

既定のパラメータ
Scalaでは、特定の関数を呼び出すときに、パラメータの具体的な値を指定せずに、パラメータ自体のデフォルト値を使用したい場合があります.この場合、関数を定義するときにデフォルトパラメータを使用するように定義されます.
def sayHello(firstName: String, middleName: String = "William", lastName: String = "Croft") = firstName + " " + middleName + " " + lastName 

与えられたパラメータが足りない場合は、パラメータが左から右に順に適用されます.
JavaとScalaはデフォルトのパラメータの違いを実現します
Java:
public void sayHello(String name, int age) {
  if(name == null) {
    name = "defaultName"
  }
  if(age == 0) {
    age = 18
  }
}
sayHello(null, 0)

Scala:
def sayHello(name: String, age: Int = 20) {
  print("Hello, " + name + ", your age is " + age)
}
sayHello("leo")

バンド名パラメータ
関数を呼び出すときは、関数定義のパラメータ順ではなく、名前付きパラメータで渡すこともできます.
sayHello(firstName = "Mick", lastName = "Nina", middleName = "Jack") 

また、未命名パラメータと帯名パラメータを混合して使用することもできますが、未命名パラメータは帯名パラメータの前に配置する必要があります.
sayHello("Mick", lastName = "Nina", middleName = "Jack")

のびパラメータ
Scalaでは、パラメータの個数が可変な形式として定義する必要がある場合があります.この場合、変長パラメータを使用して関数を定義できます.
def sum(nums: Int*) = {
  var res = 0
  for (num 

シーケンス呼び出しの長さパラメータの使用
既存のシーケンスを直接長くなるパラメータ関数を呼び出す場合は、正しくありません.たとえばval s=sum(1 to 5).この場合はScalaの特殊な構文を用いてパラメータをシーケンスとして定義し,Scala解釈器が認識できるようにする必要がある.この文法はとても役に立ちます.ぜひよく考えて、sparkのソースコードに大量に使用しました.
val s = sum(1 to 5: _*)

ケース:再帰関数を使用した累積
def sum2(nums: Int*): Int = {
  if (nums.length == 0) 0
  else nums.head + sum2(nums.tail: _*)
}

かんすうてつづき
Scalaでは、関数を定義するときに、=接続を使用せずに関数体がカッコ内に直接包まれている場合、関数の戻り値のタイプがUnitになります.このような関数をプロセスと呼ぶ.プロシージャは、通常、値を返す必要のない関数に使用されます.
プロシージャには、関数の戻り値タイプをUnitとして定義する書き方もあります.
def sayHello(name: String) = "Hello, " + name
def sayHello(name: String) { print("Hello, " + name); "Hello, " + name }
def sayHello(name: String): Unit = "Hello, " + name

Lazy値
Scalaでは、lazy値の特性が提供されます.つまり、変数をlazyとして宣言すると、変数に対応する式が計算されるのは、変数が初めて使用されたときだけです.この特性は、ファイルを開いてIOを行い、ネットワークIOを行うなど、特に時間のかかる計算操作に特に有用である.
import scala.io.Source._
lazy val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString

ファイルが存在しなくてもエラーは報告されず,変数を最初に使用した場合にのみエラーが報告され,式計算のlazy特性が証明された.
val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString
lazy val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString
def lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString

異常
Scalaでは,例外処理とキャプチャメカニズムはJavaと非常に類似している.
try {
  throw new IllegalArgumentException("x should not be negative")
} catch {
  case _: IllegalArgumentException => println("Illegal Argument!")
} finally {
  print("release resources!")
}

try {
  throw new IOException("user defined exception")
} catch {
  case e1: IllegalArgumentException => println("illegal argument")
  case e2: IOException => println("io exception")
}

小結
1、個人的にはscalaの関数はjavaよりも簡潔になったと思います.
2、いくつかのパラメータ、戻り値、lazyメカニズムはコードをより簡潔にし、プログラムをより安定させた.