Skip to content

Instantly share code, notes, and snippets.

@fuyufjh
Last active July 15, 2018 16:00

Revisions

  1. fuyufjh revised this gist Jul 15, 2018. 2 changed files with 60 additions and 0 deletions.
    33 changes: 33 additions & 0 deletions akka.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,33 @@
    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)
    }
    27 changes: 27 additions & 0 deletions cheatsheet.scala
    Original file line number Diff line number Diff line change
    @@ -389,3 +389,30 @@ def factorial(fact: BigInt, number: Int): BigInt = {
    }
    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()
  2. fuyufjh created this gist Jul 11, 2018.
    391 changes: 391 additions & 0 deletions cheatsheet.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,391 @@
    // 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", "venkats@agiledeveloper.com")
    }
    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))