Scalaが難しいので初歩の初歩からやり直すことにした(その3)

object HelloWorld {
  def main(args: Array[String]): Unit = {
    System.out.println("Hello, Scala!")
  }
}

二行目

  def main(args: Array[String]): Unit = {
  • 「def」ってなんだよ!!!

関数を定義するキーワードです。

  • 「Unit」ってなんだよ!!!

関数の戻り値がないときに戻り値の型として指定します。voidみたいなもの。厳密に言うとvoidとは違うらしいのですが、「最初はそんな感じの理解で充分だよ」ってどっかに書いてたので、そんな感じで理解しておきます。

  • 「=」が付いてるけど、これは代入式なのか? 関数定義なのか?!

関数もオブジェクトなので変数に代入できます。

  • 関数定義っぽいけど「public static」はいらないの?何も書かなかったらデフォルトでstaticメソッドになるのか?!

Scalaには「static」というキーワードが存在しない。staticなオブジェクトは シングルトンオブジェクトとして「object」キーワードで定義する。staticなメソッドはシングルトンなオブジェクトのメソッドとして生きる。

色々やってみた結果「def」

関数

import java.util.Date

// 現在の日付を返す関数
def getDate :String = {
  (new Date).toString
}


関数の中身が一行だったらニョロカッコは省略できます。

def getDate :String = (new Date).toString


戻り値の型はコンパイラが空気読んでくれるので、これも省略できます。

def getDate = (new Date).toString


『オブジェクト dot メソッド』は、『オブジェクト (半角スペース) メソッド』って書いても動きます。

def getDate = new Date toString


呼び出すときはこう

getDate // <- Thu Mar 20 03:44:36 JST 2008

引数を受け取る関数

def add( i :Int, j :Int ) = i + j


引数を受け取る関数その2
引数を「値」ではなく「名前」で受け取る。
「値」で受け取る場合、引数は評価されてから渡されます。「名前」で受け取る場合は評価せずにそのまんま渡して、関数の中で評価が行われます。
関数名をそのまんま引数に渡したら、2つの違いが分かりました。

def returnFive = {
  println( "5を返すよ" );
  5
}

def factorialByName( num: => Int ) = num * num // 名前渡し
def factorialByValue( num :Int ) = num * num   // 値渡し

// returnFive関数はfactorialByName関数の中で実行される。(2回呼ばれる)
factorialByName( returnFive )

// returnFive関数は今この場ですぐに実行される。
factorialByValue( returnFive )


引数を受け取る関数その3
引数の型の後ろに「*」をつけると、C言語の「printf」関数みたいに、引数の数を可変長にすることができます。

def someArgs( num :Int* ) = println( num.length )

呼び出すときはこう

someArgs( 1, 2, 3, 4, 5 )  // <- 5
someArgs( 6 )              // <- 1
someArgs()                 // <- 0
someArgs                   // エラー!


可変長の引数は scala.runtime.Boxed***Array クラスのオブジェクトになります。(配列みたいなもの?)

// 複数の文字列を出力する関数
def printStrings( str :String* ) = for( s <- str ) println( s )

printStrings( "This", "is", "a", "pen" )
This
is
a
pen


可変にできるのは最後の引数だけです。

def someArgs( num :Int*, str :String* ) = println( num.length )

第一引数も第二引数も可変長にしようとするとエラーになりました。

<console>:4: error: *-parameter must come last
                    (「*」付きの引数は最後に来ないとダメだよ)
       def someArgs( num :Int*, str :String* ) = println( num.length )
                     ^

色々やってみた結果「Unit」

何も返さない関数から何かが返ってきました。

def noReturn :Unit = {}
val unit = noReturn


出力してみよう

println( "unit=" + unit )
println( "  className=" + unit.getClass.getName )
println( "  string=" + unit.toString )
println( "  hashCode=" + unit.hashCode )

結果

unit=()
  className=scala.Predef$$anon$1
  string=()
  hashCode=0

うーん・・・
()っていうのがキーワードみたいです。

色々やってみた結果 「関数オブジェクト」

def function( i :Int, j :Int ) = i + j

「function」は関数

val functionObject = function

<console>:5: error: missing arguments for method function in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
       val functionObject = function
                            ^

代入できないじゃないか!!
うそつき!!


エラーメッセージの中に「アンダーバーがどうのこうの」って書いていたので、関数名の後ろに「_」(アンダーバー)をつけてみたら、オブジェクトとして扱えました。

val functionObject = function _

関数オブジェクトの「apply」メソッドで、関数を実行できました。JavaScriptみたいです。

functionObject.apply( 1, 2 )