Last active
July 15, 2018 16:00
-
-
Save fuyufjh/64bfba3c6989aaafacc69689ef76aba1 to your computer and use it in GitHub Desktop.
Scala Cheatsheet
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import akka.actor._ | |
import akka.pattern.ask | |
import scala.collection.mutable | |
import scala.concurrent.Await | |
import scala.concurrent.duration._ | |
case class AddCount(word: String) | |
case class ReportCount(word: String) | |
class WordCountActor extends Actor { | |
private val counter = mutable.Map[String, Int]() | |
override def receive: Receive = { | |
case AddCount(word) => | |
counter.put(word, counter.getOrElse(word, 0)) | |
case ReportCount(word) => | |
sender ! counter.getOrElse(word, 0) | |
} | |
} | |
object UseActor extends App { | |
val system = ActorSystem("example") | |
val counter = system.actorOf(Props[WordCountActor]) | |
counter ! AddCount("hello") | |
counter ! AddCount("world") | |
val resultFuture = counter ? ReportCount("hello") | |
println(s"Count of 'hello' is ${Await.result(resultFuture, 2.seconds)}") | |
val terminateFuture = system.terminate() | |
Await.ready(terminateFuture, Duration.Inf) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// For loop | |
for (i <- 1 to 3) { | |
print(s"$i,") // got: 1,2,3, | |
} | |
for (i <- 1 until 3) { | |
print(s"$i,") // got: 1,2, | |
} | |
(1 to 3).foreach(i => print(s"$i,")) | |
// Tuple and multiple return values | |
def getPersonInfo(primaryKey: Int): (String, String, String) = { | |
("Venkat", "Subramanian", "[email protected]") | |
} | |
val (firstName, lastName, emailAddress) = getPersonInfo(123) | |
// Variable number of arguments | |
def max(values: Int*): Int = { | |
values.foldLeft(values(0))(Math.max) | |
} | |
max(2, 5, 3, 7, 1, 6) | |
// Default values for argument | |
def mail(destination: String = "head office", mailClass: String = "first"): Unit = { | |
println(s"sending to $destination by $mailClass class") | |
} | |
mail("Houston office", "Priority") | |
mail("Houston office") | |
mail() | |
// Named argument | |
mail(mailClass = "Priority", destination = "Houston office") | |
// Implicit parameters | |
class Wifi(name: String) { | |
override def toString = name | |
} | |
def connectToNetwork(user: String)(implicit wifi: Wifi) { | |
println(s"User: $user connected to WIFI $wifi") | |
} | |
def atOffice(): Unit = { | |
implicit def officeNetwork: Wifi = new Wifi("office-network") | |
connectToNetwork("Jill Coder") | |
connectToNetwork("Jill Coder")(officeNetwork) // equivalent | |
} | |
atOffice() | |
// Multiline String | |
val str = """In his famous inaugural speech, John F. Kennedy said | |
|"And so, my fellow Americans: ask not what your country can do | |
|for you-ask what you can do for your country." He then proceeded | |
|to speak to the citizens of the World...""" | |
println(str) | |
// String interpolation | |
val product = "ticket" | |
val price = 25.12 | |
val discount = 10 | |
println(s"On $product $discount% saves $$${price * discount / 100.00}") // s-interpolator | |
println(f"On $product%s $discount%% saves $$${price * discount / 100.00}%2.2f") // f-interpolator | |
// Operator overload | |
case class Complex(real: Double, imaginary: Double) { | |
def +(o: Complex): Complex = Complex(real + o.real, imaginary + o.imaginary) | |
def *(o: Complex): Complex = Complex(real * o.real - imaginary * o.imaginary, real * o.imaginary + imaginary * o.real) | |
override def toString: String = f"$real%f$imaginary%+fi" | |
} | |
val c1 = Complex(1, 4) | |
val c2 = Complex(2, -3) | |
val c3 = Complex(2, 2) | |
println(s"$c1 + $c2 * $c3 = ${c1 + c2 * c3}") // Multiply first, then add | |
// Equality | |
val str1 = "hello" | |
val str2 = new String("hello") | |
println(str1 == str2) // Got true, equivalent to Java's str1.equals(str2) | |
println(str1 eq str2) // Got false, equivalent to Java's str1 == str2 | |
// A simple class | |
class Person(val firstName: String, val lastName: String) { | |
var position: String = _ // default initial value (null for AnyRef) | |
println(s"Creating $toString") // this line is part of constructor | |
def this(firstName: String, lastName: String, position: String) { // auxiliary constructor | |
this(firstName, lastName) // must call primary constructor first | |
this.position = position | |
} | |
override def toString = s"$firstName $lastName holds $position position" | |
} | |
val john = new Person("John", "Smith", "Analyst") | |
val bill = new Person("Bill", "Walker") | |
// Type alias | |
class PoliceOfficer(val name: String) | |
object CopApp extends App { | |
type Cop = PoliceOfficer | |
val topCop = new Cop("Jack") | |
} | |
// Class inherit (the override keyword) | |
class Vehicle(val id: Int, val year: Int) { | |
override def toString = s"ID: $id Year: $year" | |
} | |
class Car(override val id: Int, override val year: Int, var fuelLevel: Int) extends Vehicle(id, year) { | |
override def toString = s"${super.toString} Fuel Level: $fuelLevel" | |
} | |
// Type Parameters (generic class) | |
class Message[T](val content: T) { | |
override def toString = s"message content is $content" | |
def is(value: T) = value == content | |
} | |
// Companion object | |
class Marker private (val color: String) { // private primary constructor | |
override def toString = s"marker color $color" | |
} | |
object Marker { | |
def getMarker(color: String): Marker = new Marker(color) | |
def apply(color: String): Marker = new Marker(color) | |
} | |
println(Marker.getMarker("blue")) | |
println(Marker("blue")) // equivalent to Marker.apply | |
// Enumeration class | |
object Currency extends Enumeration { | |
type Currency = Value // 'Currency' is not only an object but also a class, so that you may use 'val c: Currency' | |
val CNY, GBP, INR, JPY, USD = Value | |
} | |
import java.time.DayOfWeek | |
import Currency._ | |
val currency: Currency | |
Currency.values.foreach(c => println(c)) | |
// Package object | |
/* | |
package foo | |
package object bar { | |
def func() = ... | |
} | |
*/ | |
// Generics (Type Inference) | |
def someOp(number: Int) = { // So result is Int because Nothing is always subclass of other classes | |
if (number < 10) number * 2 // this branch returns Int | |
else throw new IllegalArgumentException // this branch returns Nothing | |
} | |
// Option type | |
def commentOnPractice(input: String): Option[String] = { | |
input match { | |
case "test" => Some("good") | |
case "hack" => Some("bad") | |
case _ => None | |
} | |
} | |
val comment = commentOnPractice("hack") | |
println(comment.getOrElse("Found no comment")) | |
// Either type | |
def compute(input: Double): Either[String, Double] = { | |
if (input > 0) Right(math.sqrt(input)) // usually Right for normal result | |
else Left("Error: invalid input") // ... and Left for error | |
} | |
def displayResult(result: Either[String, Double]): Unit = { | |
result match { | |
case Right(value) => println(s"result: $value") | |
case Left(error) => println(s"error: $error") | |
} | |
} | |
displayResult(compute(1.2)) | |
// Support covariance (accept any subclass) | |
class Pet(val name: String) { | |
override def toString: String = name | |
} | |
class Cat(override val name: String) extends Pet(name) | |
def payWithPets[T <: Pet](pets: Array[T]): Unit = { | |
println("Playing with pets: " + pets.mkString(", ")) | |
} | |
val cats = Array(new Cat("Rover"), new Cat("Comet")) | |
payWithPets(cats) // OK! | |
// Support contravariance (accept any superclass) | |
def copyPets[S, D >: S](fromPets: Array[S], toPets: Array[D]): Unit = { | |
for (i <- fromPets.indices) toPets(i) = fromPets(i) | |
} | |
val pets = new Array[Pet](10) | |
copyPets(cats, pets) // OK! | |
// Support covariance/contravariance for customized collection | |
class MyList[+T] // ... | |
val list: MyList[Any] = new MyList[Int] // OK! | |
// Implicit function | |
class DateHelper(offset: Int) { | |
def days(when: String) = { | |
val today = java.time.LocalDate.now | |
when match { | |
case "ago" => today.minusDays(offset) | |
case "from_now" => today.plusDays(offset) | |
} | |
} | |
} | |
object DateHelper { | |
import scala.language.implicitConversions // otherwise the compiler will complain about 'implicit' keyword | |
val ago = "ago" | |
val from_now = "from_now" | |
implicit def convertInt2DateHelper(offset: Int): DateHelper = new DateHelper(offset) | |
} | |
{ | |
import DateHelper._ | |
println(2 days ago) | |
} | |
// Implicit class | |
object DateUtil { | |
val ago = "ago" | |
val from_now = "from_now" | |
implicit class DateHelper(val offset: Int) extends AnyVal { // 'extends AnyVal' eliminates the cost of newing object | |
def days(when: String) = { | |
val today = java.time.LocalDate.now | |
when match { | |
case "ago" => today.minusDays(offset) | |
case "from_now" => today.plusDays(offset) | |
} | |
} | |
} | |
} | |
{ | |
import DateUtil._ | |
println(2 days ago) | |
} | |
// String interpolator | |
val expr1 = "expr1" | |
val expr2 = "expr2" | |
val text1 = s"text1 $expr1 text2 $expr2" // Equivalent to: new StringContext("text1 ", " text2 ", "").s(expr1, expr2) | |
// High-order function | |
def printValue(generator: () => Int): Unit = { | |
println(s"Generated value is ${generator()}") | |
} | |
printValue(() => 42) | |
// Currying | |
val array = Array(2, 3, 5, 1, 6, 4) | |
def inject(arr: Array[Int], initial: Int)(operation: (Int, Int) => Int): Int = { // similar with `foldLeft` | |
var carryOver = initial | |
for (element <- array) carryOver = operation(carryOver, element) | |
carryOver | |
} | |
val sum = inject(array, 0)((sum, elem) => sum + elem) // array.sum | |
val max = inject(array, Integer.MIN_VALUE) { (large, elem) => Math.max(large, elem) } // array.max | |
// Parameter routing (simplify) | |
val largest1 = (Integer.MAX_VALUE /: array) { (carry, elem) => Math.max(carry, elem) } | |
val largest2 = (Integer.MAX_VALUE /: array) { Math.max(_, _) } | |
val largest3 = (Integer.MAX_VALUE /: array) { Math.max _ } // '_' represents list of arguments | |
val largest4 = (Integer.MAX_VALUE /: array) { Math.max } | |
// Partial function | |
def log(date: java.util.Date, message: String): Unit = { | |
println(s"$date --- $message") | |
} | |
val dateToday = new java.util.Date() | |
val logWithData = log(dateToday, _: String) // logWithData: String => Unit | |
logWithData("some message") | |
// Pass code block and wrap around | |
class Resource private { | |
println("starting") | |
def doSomething(): Unit = { println("do something") } | |
private def cleanUp(): Unit = { println("ending") } | |
} | |
object Resource { | |
def use(codeBlock: Resource => Unit): Unit = { | |
val resource = new Resource | |
try { | |
codeBlock(resource) | |
} finally { | |
resource.cleanUp() | |
} | |
} | |
} | |
Resource.use(resource => { // Execute Around Method design pattern | |
resource.doSomething() | |
}) | |
// Trait (class) | |
trait Friend { | |
val name: String // no actual value, so it's abstract | |
def listen(): Unit = println(s"Your friend $name is listening") | |
} | |
class Human(val name: String) extends Friend | |
class Man(override val name: String) extends Human(name) | |
abstract class Animal | |
class Dog(val name: String) extends Animal with Friend | |
new Man("jason").listen() | |
new Dog("husky").listen() | |
// Mix-in trait into an instance | |
class Cat(val name: String) extends Animal | |
val angel = new Cat("Angel") with Friend | |
angel.listen() | |
// Set and Map | |
val mySet = Set("foo", "bar") | |
val myMap = Map("foo" -> 1, "bar" -> 2) | |
myMap.get("foo") // got Option[Int] | |
myMap("foo") // may throw NoSuchElementException | |
// Methods end with some special characters will be bind to the second variable (':', '+', '-', '!', '~') | |
class Sample { | |
def unary_!(): Unit = println("called unary '!'") | |
} | |
val sample = new Sample | |
!sample | |
// List | |
val listExample = List("foo", "bar") | |
"hello" :: listExample // prepend | |
List("hello", "world") ::: listExample // prepend | |
// For expression | |
for (_ <- 1 to 3) print("ho ") | |
for (i <- 1 to 9; j <- i to 9) println(s"$i * $j = ${i * j}") | |
// For ... yield (generator) | |
val doubles = for (i <- 1 to 9) yield i * 2 | |
val doubles2 = for (i <- 1 to 9; result = i * 2) yield result | |
val doubleEvens = for (i <- 1 to 9; if i % 2 == 0) yield i * 2 | |
val doubleEvens2 = for (i <- 1 to 9; result = i * 2; if i % 2 == 0) yield result | |
// Pattern match: constants | |
var input: Any | |
input match { | |
case "day" => println("matched day") | |
case DayOfWeek.FRIDAY => println("matched Friday") | |
case _ => println("not matched") | |
} | |
// Pattern match: lists and tuples | |
input match { | |
case ("hello", name) => println(s"hello $name") | |
case (foo, bar) => println(s"tuple $foo $bar") | |
} | |
input match { | |
case List("apple") => println("apple only") | |
case List("red", "blue", _*) => println(s"colors red, blue, ...") | |
} | |
// Pattern match: type | |
input match { | |
case x: Int => print(s"got int $x") | |
case s: String => printf(s"got string $s") | |
case (v1: Int, v2: Int) => print(s"got pair of int $v1 $v2") | |
} | |
// Pattern match with defence | |
input match { | |
case x: Int if x > 1000 => print(s"got big int $x") | |
case x: Int => print(s"got int $x") | |
} | |
// Pattern match: case classes | |
trait Trade | |
case class Buy(stock: String, quantity: Int) extends Trade | |
case class Sell(stock: String, quantity: Int) extends Trade | |
var trade: Trade | |
trade match { | |
case Buy(stock, quantity) => print(s"Buying $quantity units of $stock") // unapply() is called | |
case Sell(stock, quantity) => print(s"Selling $quantity units of $stock") | |
} | |
// Exception handling (try-catch) | |
try { | |
Integer.parseInt("12.34") | |
} catch { | |
case e: NumberFormatException => print(s"number format error: ${e.getMessage}") | |
case _: Throwable => print("something went wrong") | |
} | |
// Tail recursion (TCO) | |
@scala.annotation.tailrec // ensure TCO | |
def factorial(fact: BigInt, number: Int): BigInt = { | |
if (number == 0) fact | |
else factorial(fact * number, number - 1) | |
} | |
println(factorial(1, 1000)) | |
// Lazy value | |
lazy val lazyValue = System.currentTimeMillis | |
// Non-strict (lazy) view of strict collections (like `stream()` in Java) | |
val people = List(("Mark", 32), ("Bob", 22), ("Jane", 8), ("Jill", 21), ("Nick", 50), ("Nancy", 42)) | |
people.filter(_._2 > 17).filter(_._1.startsWith("J")).head | |
people.view.filter(_._2 > 17).filter(_._1.startsWith("J")).head // compute lazily | |
// Stream | |
def generate(starting: Int = 0): Stream[Int] = starting #:: generate(starting + 1) // "#::" means concat lazily | |
println(generate()) // got Stream(0, ?) | |
println(generate().take(10).force) // got Stream(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) | |
println(generate().take(10).toList) // got List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) | |
// Parallel collections | |
def squareSlow(input: Int): Int = { | |
println(s"computing square for $input ...") | |
Thread.sleep(1000) | |
input * input | |
} | |
val inputs = List(1, 2, 3, 4, 5) | |
inputs.map(squareSlow) // cost 5 secs | |
inputs.par.map(squareSlow) // cost 1 secs | |
// Input from console | |
import scala.io.StdIn | |
val symbol = StdIn.readLine() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment