Searching...
miércoles, 17 de mayo de 2023

Scala Cheat Sheet

 This cheat sheet originated from the #progfun forum, credits to Laurent Poulain. We copied it and changed or added a few things. There are certainly a lot of things that can be improved! If you would like to contribute, you have two options:

Evaluation Rules

  • Call by value: evaluates the function arguments before calling the function

  • Call by name: evaluates the function first, and then evaluates the arguments if need be

Higher order functions

These are functions that take a function as a parameter or return functions.

Currying

Converting a function with multiple arguments into a function with a single argument that returns another function.

Classes

this references the current object, assert(<condition>) issues AssertionError if condition is not met. See scala.Predef for require, assume and assert.

Operators

myObject myMethod 1 is the same as calling myObject.myMethod(1)

Operator (i.e. function) names can be alphanumeric, symbolic (e.g. x1, *, +?%&, vector_++, counter_=)

The precedence of an operator is determined by its first character, with the following increasing order of priority:

The associativity of an operator is determined by its last character: Right-associative if ending with :, Left-associative otherwise.

Note that assignment operators have lowest precedence. (Read Scala Language Specification 2.9 sections 6.12.3, 6.12.4 for more info)

Class hierarchies

To create an runnable application in Scala:

or

Class Organization

  • Classes and objects are organized in packages (package myPackage).

  • They can be referenced through import statements (import myPackage.MyClass, import myPackage._, import myPackage.{MyClass1, MyClass2}, import myPackage.{MyClass1 => A})

  • They can also be directly referenced in the code with the fully qualified name (new myPackage.MyClass1)

  • All members of packages scala and java.lang as well as all members of the object scala.Predef are automatically imported.

  • Traits are similar to Java interfaces, except they can have non-abstract members:trait Planar { ... } class Square extends Shape with Planar

  • General object hierarchy:

- scala.Any base type of all types. Has methods hashCode and toString that can be overridden

- scala.AnyVal base type of all primitive types. (scala.Double, scala.Float, etc.)

- scala.AnyRef base type of all reference types. (alias of java.lang.Object, supertype of java.lang.String, scala.List, any user-defined class)

- scala.Null is a subtype of any scala.AnyRef (null is the only instance of type Null), and scala.Nothing is a subtype of any other type without any instance.

Type Parameters

Similar to C++ templates or Java generics. These can apply to classes, traits or functions.

It is possible to restrict the type being used, e.g.

Variance

Given A <: B

If C[A] <: C[B], C is covariant

If C[A] >: C[B], C is contravariant

Otherwise C is nonvariant

For a function, if A2 <: A1 and B1 <: B2, then A1 => B1 <: A2 => B2.

Functions must be contravariant in their argument types and covariant in their result types, e.g.

Find out more about variance in lecture 4.4.

Pattern Matching

Pattern matching is used for decomposing data structures:

Here are a few example patterns

The last example shows that every pattern consists of sub-patterns: it only matches lists with at least one element, where that element is a pair. x and y are again patterns that could match only specific types.

Options

Pattern matching can also be used for Option values. Some functions (like Map.get) return a value of type Option[T] which is either a value of type Some[T] or the value None:

Most of the times when you write a pattern match on an option value, the same expression can be written more concisely using combinator methods of the Option class. For example, the function getMapValue can be written as follows:

Pattern Matching in Anonymous Functions

Pattern matches are also used quite often in anonymous functions:

Instead of p => p match { case ... }, you can simply write {case ...}, so the above example becomes more concise:

Collections

Scala defines several collection classes:

Base Classes

  • Iterable (collections you can iterate on)

  • Seq (ordered sequences)

  • Set

  • Map (lookup data structure)

Immutable Collections

  • List (linked list, provides fast sequential access)

  • Stream (same as List, except that the tail is evaluated only on demand)

  • Vector (array-like type, implemented as tree of blocks, provides fast random access)

  • Range (ordered sequence of integers with equal spacing)

  • String (Java type, implicitly converted to a character sequence, so you can treat every string like a Seq[Char])

  • Map (collection that maps keys to values)

  • Set (collection without duplicate elements)

Mutable Collections

  • Array (Scala arrays are native JVM arrays at runtime, therefore they are very performant)

  • Scala also has mutable maps and sets; these should only be used if there are performance issues with immutable types

Examples

Pairs (similar for larger Tuples)

Ordering

There is already a class in the standard library that represents orderings: scala.math.Ordering[T] which contains comparison functions such as lt() and gt() for standard types. Types with a single natural ordering should inherit from the trait scala.math.Ordered[T].

For-Comprehensions

A for-comprehension is syntactic sugar for map, flatMap and filter operations on collections.

The general form is for (s) yield e

  • s is a sequence of generators and filters

  • p <- e is a generator

  • if f is a filter

  • If there are several generators (equivalent of a nested loop), the last generator varies faster than the first

  • You can use { s } instead of ( s ) if you want to use multiple lines without requiring semicolons

  • e is an element of the resulting collection

Example 1

is equivalent to

Translation Rules

A for-expression looks like a traditional for loop but works differently internally

for (x <- e1) yield e2 is translated to e1.map(x => e2)

for (x <- e1 if f) yield e2 is translated to for (x <- e1.filter(x => f)) yield e2

for (x <- e1; y <- e2) yield e3 is translated to e1.flatMap(x => for (y <- e2) yield e3)

This means you can use a for-comprehension for your own type, as long as you define map, flatMap and filter.

Example 2

is equivalent to

is equivalent to


0 comentarios:

Publicar un comentario

Gracias por participar en esta página.

 
Back to top!