Methods
Return types can be inferred, but always annotate public methods.
8.1 Defining methods
Return types can be inferred, but always annotate public methods. Recursive methods require an explicit return type.
def add(a: Int, b: Int): Int = a + b
def greet(name: String): String =
val msg = s"Hello, $name"
msg + "!"
def log(msg: String): Unit = println(msg)8.2 Default and named arguments
def connect(host: String = "localhost", port: Int = 8080, secure: Boolean = false): String =
s"${if secure then "https" else "http"}://$host:$port"
connect() // http://localhost:8080
connect(port = 9000) // named
connect("example.com", secure = true)8.3 Varargs
def sum(nums: Int*): Int = nums.sum
sum(1, 2, 3)
val list = List(1, 2, 3)
sum(list*) // spread (Scala 2: list: _*)8.4 Multiple parameter lists (currying)
def add(a: Int)(b: Int): Int = a + b
val add5 = add(5) // Int => Int (eta-expansion is automatic in Scala 3)
add5(10) // 15
def withResource[A](name: String)(body: String => A): A = body(name)
withResource("file.txt") { f =>
s"processing $f"
}8.5 By-name parameters
def time[A](block: => A): A =
val start = System.nanoTime()
val result = block // evaluated here, lazily
println(s"${(System.nanoTime() - start) / 1e6} ms")
result
time { Thread.sleep(100); 42 }8.6 Nested methods & procedures
def factorial(n: Int): BigInt =
def loop(n: Int, acc: BigInt): BigInt =
if n <= 1 then acc else loop(n - 1, acc * n)
loop(n, 1)8.7 Infix and symbolic methods
case class Vec(x: Double, y: Double):
def +(o: Vec): Vec = Vec(x + o.x, y + o.y)
def *(k: Double): Vec = Vec(x * k, y * k)
infix def dot(o: Vec): Double = x * o.x + y * o.y
def unary_- : Vec = Vec(-x, -y)
val v = Vec(1, 2) + Vec(3, 4) * 2
val d = Vec(1, 0) dot Vec(0, 1)
val n = -v8.8 apply & update
class Matrix(data: Array[Array[Int]]):
def apply(i: Int, j: Int): Int = data(i)(j)
def update(i: Int, j: Int, v: Int): Unit = data(i)(j) = v
val m = Matrix(Array.ofDim[Int](2, 2))
m(0, 1) = 5 // m.update(0, 1, 5)
m(0, 1) // m.apply(0, 1)