他の多くのチュートリアルがそうであるように、私たちもまずはScalaの世界にあいさつすることから始めましょう。
''hello.scala''というファイルを作り(Scalaではソースファイルに''.scala''という拡張子を付けることが通例となっています)、次のように書いて保存して下さい。
[https://paiza.io/projects/QNLS9UYljt6PgoAzPZPWbA?language=scala hello.scala]:
object Main extends App{
    println("Hello world!")
}
Scalaには、一般的なプログラミング言語と同様に、コード内にコメントを挿入する機能があります。Scalaのコメントは、Javaと同様に、複数行コメントや単一行コメントの形式をサポートしています。以下に、Scalaでのコメントの例を示します。
// これは単一行コメントです。
/*
   これは
   複数行コメントです。
/** 
  * これはドキュメンテーションコメントです。
  * ScalaDoc形式のコメントで、関数やクラスのドキュメントを生成するために使用されます。
  */
また、ScalaではScalaDocというドキュメンテーションツールを使用して、ソースコード内のコメントからドキュメントを生成することができます。このようなコメントは、コードの可読性やメンテナンス性を向上させるために重要です。
ScalaDocは、Scalaのソースコード内に記述されたコメントから自動的にドキュメントを生成するツールです。JavaのJavadocに似ていますが、Scalaの特性に合わせて拡張されたものです。
ScalaDocは、特定の形式のコメントに基づいて、ソースコードのAPIドキュメントを生成します。主な特徴は次のとおりです：
コメントの形式: ScalaDocは、コメントが/** */で囲まれていることを前提としています。これにより、複数行のコメントや特定のタグを含むことができます。
タグ: ScalaDocコメントには、さまざまなタグを使用して特定の情報を指定できます。例えば、@paramタグは関数のパラメータに関する情報を提供し、@returnタグは関数の戻り値に関する情報を提供します。
HTML出力: ScalaDocは通常、HTML形式のドキュメントを生成します。これにより、ブラウザで簡単に参照できる形式でAPIドキュメントを提供できます。
ScalaDocを使用することで、ソースコードの理解や使用方法のドキュメント化が容易になります。特に大規模なプロジェクトやライブラリでは、正確で明確なドキュメントは非常に重要です。
以下は、ScalaDocの例です。これは、簡単なScalaのクラスとそのメソッドのドキュメントを示しています。
 
/**
  * This is a simple class representing a point in 2D space.
  *
  * @param x The x-coordinate of the point.
  * @param y The y-coordinate of the point.
  */
class Point(val x: Double, val y: Double) {
  
  /**
    * Calculates the distance between this point and another point.
    *
    * @param other The other point to calculate the distance to.
    * @return The distance between this point and the other point.
    */
  def distanceTo(other: Point): Double = {
    val dx = this.x - other.x
    val dy = this.y - other.y
    math.sqrt(dx * dx + dy * dy)
  }
}
/**
  * Main entry point of the program.
  */
object Main extends App {
  val p1 = new Point(0, 0)
  val p2 = new Point(3, 4)
  
  println(s"Distance between p1 and p2: ${p1.distanceTo(p2)}")
}
この例では、Pointクラスとそのメソッドに対するScalaDocコメントが提供されています。これにより、コードを理解する人や、このクラスやメソッドを使用する人が、それらの動作や使い方について理解しやすくなります。また、ScalaDocコメントには@paramや@returnといったタグも使用されており、それぞれパラメータや戻り値に関する情報を提供しています。
Scalaの複数行コメントはネストできます。つまり、複数行コメントの中にさらに別の複数行コメントを含めることができます。これにより、コード内で複数の段落や区切りのあるコメントを組み合わせることができます。
以下は、Scalaでの複数行コメントのネストの例です。
/*
  これは外側の複数行コメントです。
  
  /*
    これは内側の複数行コメントです。
    内側のコメントは外側のコメントの中にネストされています。
  */
  
  外側のコメントは内側のコメントの外側にあります。
このように、Scalaでは複数行コメントを適切にネストすることができます。
Scalaでは、JavaScriptやGoの様に ; が自動挿入されます。
❌
 var x = 1 + 2
 + 3
⭕
 var x = 1 + 2 +
 3
Scalaは、関数型プログラミング言語ですが、純粋関数言語ではないので変数があります。
Scalaで変数を使うためには、宣言が必要です。
[https://paiza.io/projects/cQSDnyoWVrZZ1niEXur3xw?language=scala コード例]:
// val i: Int = 0 // !!! error: expected class or object definition !!!
object Main extends App {
    val i: Int = 123
    // i = 0 // !!! error: reassignment to val !!!
    println(i)
}
実行結果:
123
1行目は、Object の定義の外で宣言しようとしても失敗する例です。
Scala には、グローバル変数はありません。
// から行末まではコメントになります。
object Main の中で、Int型の変数 i を宣言し、123 で初期化しています。
val で宣言した i に 0 を代入しようとしていますがエラーになります。
println(i) の様に、変数の値は変数名（この場合は i）を使って参照できます。
[https://paiza.io/projects/m7W0SR6MfF9i4obsqJz4rg?language=scala コード例]:
// var i: Int = 0 // !!! error: expected class or object definition !!!
object Main extends App {
    var i: Int = 123
    i = 0
    println(i)
}
実行結果:
0
1行目は、Object の定義の外で宣言しようとしても失敗する例です。
ミュータブルであっても、グローバル変数は作れません。
object Main の中で、Int型の変数 i を宣言し、123 で初期化しています。
var で宣言した i には 0 を代入する事ができます。この様な変数をミュータブルな変数と言います。
[https://paiza.io/projects/j8TR9XpQJgHf-649jReSDA?language=scala コード例（コンパイルエラー）]:
object Main extends App {
    var i: Int
    println(i)
}
コンパイル結果:
1 error
Main.scala:2: error: only traits and abstract classes can have declared but undefined members
(Note that variables need to be initialized to be defined)
    var i: Int
        ^
[https://paiza.io/projects/db05Fc4iWgF226hG5uAd6Q?language=scala コード例]:
object Main extends App {
    var i: Int = _
    println(i)
    var f: Boolean = _
    println(f)
    var s: String = _
    println(s)
    var m: Map[String, Int] = _
    println(m)
}
実行結果:
0
false
null
null
識別子 _ を初期化に使うと、その型のディフォルト値で初期化されます。
数値は 0、Boolean は false、他は null がディフォルト値となります。
Go のゼロ値と似ていますが、明示的に _ で初期化するところが違います。
[https://paiza.io/projects/8kUN8FqfxdoL9YDlB37_dg?language=scala コード例]:
object Main extends App {
    val i, j, k = 42
    println(i, j, k)
    val u, v, w = new Array(5)
    println(u, v, w)
    var n: Int = 0
    val x, y, z = { n += 1 ; n }
    println(x, y, z)
}
実行結果:
(42,42,42)
([Ljava.lang.Object;@7c16905e,[Ljava.lang.Object;@2a2d45ba,[Ljava.lang.Object;@2a5ca609) 
(1,2,3)
複数の変数を、一度に宣言し同じ式値ではなく式です。で初期化することが出来ます。
val i, j, k = 42 で k だけではなく j も i も初期化されます。
初期化の式は、リテラルである必要はなく、初期化される宣言毎に評価されます。
val u, v, w = new Array(5) の new Array(5) は、３回評価され、その都度新しいインスタンスが生成されます。
val x, y, z = { n += 1 ; n } の { n += 1 ; n } は、３回評価され、その都度インクリメントされるので、C言語の列挙型 enum と同じ機能が実現できます。どちらかと言うと Goの iota ですね。
{ n += 1 } ではなく { n += 1 ; n } なのは、 n += 1 の値は n ではなく () だからです。
このため、Scala では x = y = 42 とは出来ず（x に () が入ってしまう）、(x, y) = (42, 42) のようにします。
変数宣言にもパターンマッチングが使えます。
 val (x, y) = ( 178, 901 )
 val v @ (a, a) = ( 42, 78 )
 val m @ Array(n0, n1, _*) = Array(2,3,5,7,11)
[https://paiza.io/projects/tO047BQjIHxY37OsapSNdg?language=scala コード例]:
object Main extends App {
  var a = 3
  var b = 4
  lazy val c = { println("!"); a * b }
  a = 0
  println(c)
  a = 100
  println(c)
}
実行結果:
!
0
0
この時に参照されるのは、5行目で更新された a の値が参照されるので、クロージャではありません。
8行目で再び、c を参照すると、7行目での a の変更は反映されません。一度、評価されたら値は変わりません。
lazy var は出来ません。
----
{{コラム|val? var? どちらを使うべき？|2=
変数を宣言するとき「valで宣言するか var で宣言すべきか？」、
言い換えると、「変数をイミュータブルにすべきか？」と言う質問になります。
関数プログラミングの観点からは、そもそも変数（＝副作用）は邪道なのですが、
あえて変数を使うのであれば、まず val（イミュータブル）で宣言し、代入が行われるようなら var（ミュータブル）に変更するという基本戦略が考えられます。
幸いScalaは、イミュータブルな変数とミュータブルな変数に使える名前（変数名）の規則は同じで、参照するときも追加の記号は必要ありません。
先の例では、変数を型を指定して宣言していました。
Scalaには、型推論機構があるので、初期値が与えられる変数宣言では初期値から変数の型が推論され型名を明示する必要はなくなります。
型推論:
object Main extends App {
    val i = 123
    var j = 12
    println(i)
    println(j)
}
実行結果:
123
12
Javaの数値はオブジェクトではなくプリミティブ型ですが、Scalaでは数値もオブジェクトです。
また型名にも違いがあるので、対照表にしてみました。
Scalaでは、カーリーブラケット構文を使ってブロックを表します。
ブロックの最後の式の値が、ブロックの値になります。
ブロックとブロックの値:
object Main extends {
  val x = {
    val (a, b) = (1, 2)
    println("Hello!")
    a + b
  }
  println(x)
}
実行結果:
Hello! 
3
val (a, b) = (1, 2)は、タプルを使った変数の宣言です。
これらの変数のスコープはブロック末の '}' までで、それ以降は参照できません（ブロックスコープ）。
Scalaでは、「0個以上のパラメータを受取ることの出来る式」を関数と呼びます。
他の言語では、アロー関数やラムダ式と呼ばれる概念です。
関数:
object Main extends App {
    val add = (x: Int, y: Int) => x + y
    val msg = () => "hello!"
    println(add(1, 2))
    println(add(1999, 1))
    println(msg())
    println(((a: Int,b: Int)=>a*b)(9, 11))
}
実行結果:
3
2000 
hello!
99
関数には名前がないので、変数に一旦に束縛し変数（変数名）を使って呼出します。
8行目では、変数を介さず定義したその場で実行しています（無名関数の即時実行）。
[https://paiza.io/projects/h5Hh9tmcCbXIuXc-PpZx-A?language=scala コード例]:
object Main extends App {
  println((0 to 4).map(x => x * 3))
  println((0 to 4).map(_ * 3))
  println((0 to 4).reduce((x, y) => x + y))
  println((0 to 4).reduce(_ + _))
  println((0 to 4).map(x => x * x)) // 参照が二回以上ある場合は明示的に名前をつける
}
実行結果:
Vector(0, 3, 6, 9, 12)
Vector(0, 3, 6, 9, 12)
10
10
Vector(0, 1, 4, 9, 16)
パイプラインスタイルは、JavaScriptなどでよく使うメソッドチェインですが、イテレータメソッドが演算子の様に見える書き方です。
for と Range と ifの例をパイプラインスタイルで置換えてみます。
例:
object Main extends App {
  // for (i <- 0 to 10 if i % 2 != 0) println(i)
  (0 to 10) filter { _ % 2 != 0 } foreach { println(_) }
}
実行結果:
1
3
5
7
9
関数合成ではないので、(0 to 10) filter { _ % 2 != 0 } が先に評価され、そのオブジェクトに  .foreach({ println(_) }) が提供されるので、場合によっては要素数の多いコレクション・オブジェクトが中間結果として生成されるので注意してください。
メソッドは、コードを再利用する仕組みで、関数と似ていますが、両者は別個のものです。
メソッドはclass、object、trait内でキーワードdefを使って定義します。
メソッド:
object Main extends App {
    def add(x: Int, y: Int): Int = x + y
    def msg: String = "hello!"
    println(add(1, 2))
    println(add(1999, 1))
    println(msg)
}
実行結果:
3
2000 
hello!
これだけ観ると、構文はともかく関数とメソッドの差は大きく感じられません。
強いていうと、空の引数リストは定義も呼出しも () を付けないところが違います。
これまで、頻繁に使ってきた println() も、Predefオブジェクトのメソッドで、Predefオブジェクトは暗黙に import されるので特別な準備なく使えました。
Scalaでは、メソッドや関数の引数は値渡しですが、遅延評価にすることが出来ます。
これによって、制御構造を関数定義する道が開きます。
[https://paiza.io/projects/TUhXbh6yml2ScepcpNMGoA?language=scala メソッド]:
object Main extends App {
  def f1(x: Boolean, t: Unit, f: Unit) = if (x) t else f
  f1(true, println("True"), println("False"))
  
  def f2(x: Boolean, t: => Unit, f: => Unit) = if (x) t else f
  f2(true, println("真"), println("偽"))
}
実行結果:
True
False 
真
メインメソッドは、プログラムのエントリーポイントです。
Scalaも、多くのプログラミング言語と同じく、「逐次」「分岐」「反復」の 3 種類の制御構造を持ちます。
Scalaの制御構造は、全て値を持ちます。この事は、Scalaの If式 は、C言語の三項演算子と等価であることを示します。
Scala 3 では、括弧() を使わない新しい構文が追加されました。
新構文の登場で、旧構文が使えなくなることはないので、Scala 2の為に書かれたプログラムが使えなくなるような事はありません2から3へのアップデートと言うと、python2とpython3の非互換性の悲劇を思い起こす方も多いと思いますが、Scaleでは原則的に下位互換性があります。。
if式は、条件式に基づいて分岐し分岐先の式を評価します。
if式の値は、分岐先の式の値です。
構文:
if-expr := if '(' 条件式 ')' 式1 [ else 式2 ]
条件式は、Boolean 型でなければいけません。
else 式2の部分はオプショナルで、省略され条件式が false であった場合、if式はUnit 型の値 () 単位ユニットが式の値となります（要素個数ゼロのタプルです）。
elseif elsif のたぐいはないので、else if (条件式2) 式3 と続けます。
[https://paiza.io/projects/y8p_q50uEL2IE71JfNrxNw?language=scala if式の例]:
object Main extends App {
    val i = 0
    
    if (i == 0)
        println("zero")
    else
        println("non zero")
        
    println({
        if (i == 0)
            "Zero"
        else
            "Non zero"
    })
    println({
        if (i != 0)
            "NON ZERO"
    })
}
実行結果:
zero
Zero 
()
C言語のswicth文は、式と一致するリテラルのラベルへの多方向GOTO文ですが、Scalaのmatch式はパターンマッチングに基づいています。
構文:
match-expr :=  式 match ’{’
( パターン => 式 )+
’}’
式の値に、合致するパターンはないか上から順に走査し、合致したパターン対応する式が評価され、この値がmatch式の値となります。
式に対して、パターンがどれも合致しないとコンパイル時のフロー解析の結果わかった場合、コンパイルエラーになります。
このため、全てにマッチするパターン _ が最後に置かれることが常となります。
ただし式が、Boolean や enum の場合は、網羅チェックを台無しにするので _ を使うべきではありません。
[https://paiza.io/projects/kMzZMXaBj2rARbop3Lcn0A?language=scala match式の例]:
object Main extends App {
  val n = 10
  n match {
    case 1 => println("壱")
    case 2 => println("弐")
    case 3 => println("参")
    case _ => println("多数")
  }
  
  println({
    n match {
        case 1 => "一"
        case 2 => "二"
        case 3 => "三"
        case _ => "膨大"
    }
  })
  
  println({
    n match {
        case 1 => "一"
        case 2 => "二"
        case 3 => "三"
//        case _ => "膨大" // ここをコメントにしてしまうと、網羅性がほころびコンパイルエラーになる
    }
  })
}
実行結果:
多数
膨大 
膨大
while式は、条件式が true の間、式を評価しつづけます。
while式の値は、評価した式の値です。
構文:
while-expr := while '(' 条件式 ')' 式
条件式は、Boolean 型でなければいけません。
[https://paiza.io/projects/A8RXe7wm4tuqv_N-EaeiuQ?language=scala while式の例]:
object Main extends App {
    var i = 0
    
    while (i < 5) {
        println(i)
        i += 1
    }
    println(s"last = $i")
}
実行結果:
1
2
3
4
last = 5
Scalaには、変数 ++ の様なインクリメント演算子はなく、変数 += 1 の構文を使います。
これは、Scala の整数はイミュータブルなためで、同じ理由で Ruby にもインクリメント演算子はありません。
また、変数 += 1 は、変数 = 変数 + 1の構文糖です。
さらに、変数 + 1 は、変数 .+(1)の構文糖です。
加算に限らず、Scalaの演算子は、メソッドの構文糖です。
i のスコープは、object Main なのでループを抜けても値を参照出来ます。
s"last = $i" は、加工文字列リテラル(''processed string literal'') で、文字列の中で変数の値を参照できます。
Scala 3 で、do - whileは廃止になりました。
while の条件式に繰返し部分と続行条件を書き、ループ本体は空にすることで do - while を模倣できます。
[https://paiza.io/projects/iluJn2pkYxfJwzHWflWPpw?language=scala do - while の模倣]:
object Main extends App {
    var i = 10
    
    while ({
        println(i)
        i += 1
        i < 5
    }) {}
    println(s"last = $i")
}
実行結果:
10 
last = 11
Scalaのfor式は、ジェネレータに対してイテレーションを行います。
構文:
for-expr := for '(' ジェネレータ ')' 式
[https://paiza.io/projects/eWKe2_2XTuJQPh2NzkZNTA?language=scala for式とRangeクラスの例]:
object Main extends App {
  println(0 to 4)
  for (i <- 0 to 4) println("to: " + i)
  println(0 until 4)
  for (i <- 0 until 4) println("until: " + i)
}
実行結果:
Range 0 to 4
to: 0
to: 1
to: 2
to: 3
to: 4
Range 0 until 4
until: 0
until: 1
until: 2
until: 3
class scala.collection.immutable.Range$Inclusive
0 to 4 や 0 until 4 は、Rangeクラスのオブジェクトで範囲を表します。
0.to(4) や 0.until(4) と言うメソッドの演算子表記です。
ジェネレータに、if で修飾することができます（Guardといいます）。ジェネレータ式に似た表現です。
[https://paiza.io/projects/tpIREeZXCqIKIaE81eFfcA?language=scala for式とRangeクラスとif式の例]:
object Main extends App {
  for (i <- 0 to 10 if i % 2 != 0)
    println(i)
}
実行結果:
1
3
5
7
9
２つのジェネレーターを ; で区切ると多重ループを構成出来ます。
[https://paiza.io/projects/MUXX893zSMN8DDftVS6lBQ?language=scala 二重ループ]:
object Main extends App {
  for (
    i <- 0 to 2;
    j <- 0 to 3
  ) {
    println((i, j))
  }
}
実行結果:
(0,0)
(0,1)
(0,2)
(0,3)
(1,0)
(1,1)
(1,2)
(1,3)
(2,0)
(2,1)
(2,2) 
(2,3)
for式と yeild の組合せでfor式は値を返すことが出来ます。
[https://paiza.io/projects/qqgyaWk2Of2jfOsj35RGug?language=scala 値を返す for]:
object Main extends App {
  println(for (i <- 0 to 4) yield i.toString)
}
実行結果:
Vector(0, 1, 2, 3, 4)
ブロックからの脱出には、return を使います。
break や continue はありません。
ScalaにはJavaのthrows節がありませんJavaの場合は、例外を発生させる可能性のあるメソッドは、throws節で発生させる例外の種類をすべて宣言する必要があります。
ただし、RuntimeException（RuntimeExceptionの派生クラス）の場合は、throws節で明示的に記述する必要はありません。。
すべての例外はメソッドの外側に投げることができます。
例外処理:
object Main extends App {
  try {
    val n = 1
    n / 0
    println("return!")
  } catch {
    case e: Exception => {
      println("Exception caught.")
      println(e.getMessage)
      println(e.getStackTrace)
    }
  } finally {
    println("done!")
  }
}
実行結果:
Exception caught.
/ by zero
[Ljava.lang.StackTraceElement;@35a74ae9 
done!
finally 節の式は、例外の有無に関係なく実行されます。
try 節や catch 節 で exit() すると、流石に finally 節は実行されません。
Scalaは、関数型プログラミング言語であると同時に、オブジェクト指向プログラミング言語です。
より厳密に言うと、（プロトタイプベースではなく）クラスベースのオブジェクト指向プログラミング言語です。
クラス(''class'')は、オブジェクトを作る雛形で、クラスから new 演算子を使ってオブジェクトを作ることをインスタンス化、出来たオブジェクトの事をインスタンスと呼びます。
[https://paiza.io/projects/41inK-Tl-w-FIjRvurIs3Q?language=scala コード例]:
object Main extends App {
  class Hello(val s: String = "world") {
    override def toString: String = s"Hello $s!"
    def print: Unit = println(s)
  }
  val hello1 = new Hello()
  println(hello1)
  hello1.print
  val hello2 = new Hello("my friend")
  println(hello2)
  print(s"""
Hello.getClass() === ${Hello.getClass()}
hello1 === ${hello1}
hello2.s = ${hello2.s}
""")
}
実行結果:
Hello world!
world
Hello my friend!
Hello.getClass() === class Main$Hello$
hello1 === Hello world!
hello2.s = my friend
Ruby#クラスの例を、Scala に移植しました。
冒頭4行がクラス定義です。
クラス定義に、他のオブジェクト指向言語ならコンストラクタに渡すような引数が渡されています。
メンバーを公開するケースなら、この様に宣言的な引数リストを使うとメンバー定義と暗黙の初期値を与えられます。
toString は、オブジェクトを文字列化するメソッドで、Objectの同名のメソッドをオーバーライドしています。
print は、このクラスに独自なメソッドで、println() の値 == () == Unit を戻値型としています。
Ruby#ユーザー定義クラスの都市間の大圏距離を求めるメソッドを追加した例を、Scalaに移植。
[https://paiza.io/projects/U0m9xY_SSy4X-MLnplj-0A?language=scala ユーザー定義クラス]:
object Main extends App {
  class GeoCoord(val longitude: Double = 0.0, val latitude: Double = 0.0) {
    override def toString: String = {
      var (ew, ns) = ("東経", "北緯")
      var (long, lat) = (longitude, latitude)
      if (long < 0.0) {
        ew = "西経"
        long = -long
      }
      if (lat < 0.0) {
        ns = "南緯"
        lat = -lat
      }
      s"(${ew}: ${long}, ${ns}: ${lat})"
    }
    def distance(other: GeoCoord): Double = {
      val i = Math.PI / 180
      val r = 6371.008
      Math.acos(
        Math.sin(this.latitude * i) * Math.sin(other.latitude * i) +
          Math.cos(this.latitude * i) *
          Math.cos(other.latitude * i) *
          Math.cos(this.longitude * i - other.longitude * i)
      ) * r
    }
  }
  val Sites = Map(
    "東京駅" -> new GeoCoord(139.7673068, 35.6809591),
    "シドニー・オペラハウス" -> new GeoCoord(151.215278, -33.856778),
    "グリニッジ天文台" -> new GeoCoord(-0.0014, 51.4778)
  )
  Sites.foreach { case (k, v) =>
    println(s"${k}: ${v}")
  }
  val keys = Sites.map { case (k, v) => k }.toList
  val len = keys.size
  for (i <- 0 until len) {
    val (ksi, ksx) = (keys(i), keys((i + 1) % len))
    println(s"${ksi} - ${ksx}: ${Sites(ksi).distance(Sites(ksx))} [km]")
  }
}
実行結果:
東京駅: (東経: 139.7673068, 北緯: 35.6809591)
シドニー・オペラハウス: (東経: 151.215278, 南緯: 33.856778)
グリニッジ天文台: (西経: 0.0014, 北緯: 51.4778)
東京駅 - シドニー・オペラハウス: 7823.269299386704 [km]
シドニー・オペラハウス - グリニッジ天文台: 16987.2708377249 [km]
グリニッジ天文台 - 東京駅: 9560.546566490015 [km]
[https://paiza.io/projects/R2pOOT-Yp-xk-BURc_P9Xw?language=scala コード例]:
object Main extends App {
  case class GeoCoord(longitude: Double = 0.0, latitude: Double = 0.0) {
    override def toString: String = {
      var (ew, ns) = ("東経", "北緯")
      var (long, lat) = (longitude, latitude)
      if (long < 0.0) {
        ew = "西経"
        long = -long
      }
      if (lat < 0.0) {
        ns = "南緯"
        lat = -lat
      }
      s"(${ew}: ${long}, ${ns}: ${lat})"
    }
    def distance(other: GeoCoord): Double = {
      val i = Math.PI / 180
      val r = 6371.008
      Math.acos(
        Math.sin(this.latitude * i) * Math.sin(other.latitude * i) +
          Math.cos(this.latitude * i) *
          Math.cos(other.latitude * i) *
          Math.cos(this.longitude * i - other.longitude * i)
      ) * r
    }
  }
  val Sites = Map(
    "東京駅" -> GeoCoord(139.7673068, 35.6809591),
    "シドニー・オペラハウス" -> GeoCoord(151.215278, -33.856778),
    "グリニッジ天文台" -> GeoCoord(-0.0014, 51.4778)
  )
  Sites.foreach { case (k, v) =>
    println(s"${k}: ${v}")
  }
  val keys = Sites.map { case (k, v) => k }.toList
  val len = keys.size
  for (i <- 0 until len) {
    val (ksi, ksx) = (keys(i), keys((i + 1) % len))
    println(s"${ksi} - ${ksx}: ${Sites(ksi).distance(Sites(ksx))} [km]")
  }
}
実行結果:
東京駅: (東経: 139.7673068, 北緯: 35.6809591)
シドニー・オペラハウス: (東経: 151.215278, 南緯: 33.856778)
グリニッジ天文台: (西経: 0.0014, 北緯: 51.4778)
東京駅 - シドニー・オペラハウス: 7823.269299386704 [km]
シドニー・オペラハウス - グリニッジ天文台: 16987.2708377249 [km]
グリニッジ天文台 - 東京駅: 9560.546566490015 [km]
コンストラクタ引数に val がなくても、自動的にフィールドが宣言されます。
var なフィールドを希望する場合は、var を明示します。
インスタンス化する時、new は必要ありません。
コンパニオンオブジェクトが自動的に生えてきます。
object は、たった1つのインスタンスを持つクラス（＝シングルトン）です。
これは、lazy valのように、参照されたときに（遅延して）生成されます。
object は、トップレベルの値としてはシングルトンであり、 クラスのメンバやローカルな値としては、lazy val と全く同じ振る舞いをします。
シングルトン・オブジェクトは値です。シングルトン・オブジェクトの定義はクラスのように見えますが、object というキーワードを使用します。
シンプルなシングルトン
 object Simple
トレイト(trait)は、インターフェースと抽象クラスの中間的な存在です。
実装を持ったインターフェースで、コンストラクタのパラメータを持つことができませんが、ミックスイン( ''mix-in'' )することが出来ます。
抽象クラスと同様に、トレイトは具象メンバを持つことができますが、インスタンス化することはできません。
インターフェイスと同様に、クラスは複数のトレイトのメンバを継承することができます。
クラスはトレイトで拡張することができます。
class C extends Trait1 { ... }
クラスや他の特徴を継承することができます。
trait T1 extends Class1 { ... }
trait T2 extends Trait1 { ... }
クラス、オブジェクト、トレイトはトレイトの中で混在することができます。
class C extends Trait1 with Trait2 with Trait3 { ... }
val obj = new Class1() with Trait1 with Trait2 with Trait3 { ... }