Cheet Sheet
注:该文章为笔者学习MOOC上SCALA课程时所对照的备忘录,原翻译时通过markdown记录在有道云笔记上,csdn取消了在编辑时输入md的功能因此格式会有些奇怪。
(evaluation:类似于加载到内存中,进行计算)
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
正则序求值,首先编译函数,如果需要参数的值才会去计算
``def example = 2 /evaluated when called /当被调用时才会编译``
``val example = 2 //evaluated immediately 声明时就计算``
``lazy val example = 2 //evaluated once when needed 只在需要的时候加载一次``
``def square(x: Double) //call by value应用序求值``
``def square(x: => Double) //call by name正则序求值``
``def myFct(bingdings: Int*) = {...} //bingdings is a sequence of int, containing a varying # of arguments bindings 是一个int型数据的序列,包括大量参数``
Higher order funcitons
高阶函数
These are functions that take a function as a parameter or return funcitons.
如下为参数为函数或返回值为函数的函数
``//sum() returns a function that takes two integers and returns an integer``
``//sum()函数返回一个具有两个Int输入参数,返回值也为Int类型的函数``
``def sum(f:Int => Int):(Int,Int) => Int = {``
`` def sum(a:Int, b: Int):Int = {...}``
`` sumf``
``}``
``//same as above .Its type is (Int =>Int) => (Int,Int)=> Int··
``//同上,类型为(Int =>Int) => (Int,Int)=> Int``
``def sum(f:Int => Int)(a:Int, b:Int): Int ={...}
``//Called like this``
``//如下方法调用``
``sum((x:Int) => x*x*x)`` //Anonymous function, i.e. does not have a name 匿名函数``
``sum(x =>x *x *x ) //same anonymous function with type inferred 类型推断的匿名函数``
``def cube(x:Int) = x*x*x``
``sum (x => x * x *x )(1,10) //sum of cubes from 1 to 10 求输入参数1-10的和``
``sum(cube)(1,10) //same as above 同上``
Currying
函数柯里化
Converting a function with multiple arguments into a function with a single argument that returns another function
将一个具有多个输入参数的函数转变为另一个具有唯一输入参数的函数```
```
object exercise{
// def product(f:Int => Int)(a:Int, b:Int):Int =
// if(a > b) 1
// else f(a) * product(f)(a+1, b)
//
// product(x => x * x)(3, 4) //res = 144
def mapReduce(f:Int=>Int,combine:(Int,Int) => Int.zero:Int)(a:Int,b:Int):Int=
if(a>b) zero
else combine(f(a),mapreduce(f,combine,zero)(a+1,b)
def product(f:Int=>Int)(a:Int,b:Int) :Int = mapReduce(f, (x, y) => x * y, 1)(a, b)
product(x => x * x)(3, 4) //res=144
}
```
`` def f(a:Int,b:Int):Int //uncurried version (type is (Int,Int) => Int) ``
``def f(a:int)(b:int):Int //curried version (type is Int=>Int=>Int)
``Class MyClass(x:Int,y:Int){ //Defines a new type MyClass with a constructor``
`` require(y > 0,"y ust be positive:") //precondition, triggering an IllegalArgumentException if not met``
``def this(x:Int) = {...} //auxiliary constructor``
``def nb1 = x //public method computed ecery time it is called``
``def nb2 = y``
``private def test(a:Int):Int ={...} //private method``
``val nb3 = x + y //computed only once``
``override def toString = //override method ``
`` member1 + “,”+ member2``
``}``
``new MyClass(1,2) //create a new object of tyoe``
this references the current object ,assert(<condition>) issues AssertionError if condition is not met.See scala.Predef for require,assume and assert.
引用当前对象,如果条件不符合声明断言错误(AssertionError),具体查看scala.Predef 类中assume 和assert 部分
```
final def assert(assertion:Boolean, message: => Any):Unit
Tests an expresstion, throwing an AssertionError if false.
```
```
def assert(assertion:Boolen):Unit
Tests an expression,throwing an AssertionError if false.
```
```
final def assume(assumption:Boolean, message: => Any):Unit
Tests an expression,thorwing an AssertionError if false
```
```
def assume(assumption:Boolean, message: => Any):Unit
Tests an expression,thorwing an AssertionError if false
```
```
final def require(requirement:Boolean, message:=>Any):Unit
Tests an expression, throwing an IllegalArgumentException if false
```
```
def require(requirement:Boolean, message:=>Any):Unit
Tests an expression, throwing an IllegalArgumentException if false
```
Operators
运算符
myObject myMethod 1 is the same as calling myObject.myMethod(1)
myObject myMethod 1 等价于 myObject.myMethod(1)
Operator(i.e.function) names can be alphanumeric,symbolic(e.g.x1,*,+?%&,vector_++.counter_=)
运算符(函数)名字可以是字母数字或符号(如x1,*,+?%&,vector_++.counter_=)
The precedence of an operator is determined by its first character, withthe following increasing order of priority:
运算符的优先级由他的第一个字符决定,下面的字符优先级逐个递增
```
(all letters)
|
^
&
< >
= !
:
+ -
* / %
(all other special characters)
```
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.
注意赋值运算符的优先级最低。
class C(x1,...,xn){... def f(y1,...,yn) =b...}
`The formal paramters of the class are x1,...,xn
`The class defines a method f with formal parameters y1,...,yn
expression new C(v1,....,vm).f(w1,...,wn) is rewritten to :
[w1/y1,...,wn/yn][v1/x1,...,vm/xm][newC(v1,...vm)/this]b
eg:
1. new Rational(1,2).numer
-> [1/x,2/y][][new Rational(1,2)/this]x
=1
2. new Rational(1,2).less(new Rational(2,3))
->[1/x,2/y][newRational(2,3)/that][new Rational(1,2)/this]
this.numer * that.denom < that,numer * this.denom
=new Raional(1,2).numer * new Rational(2,3).denom <
new Rational(2,3).numer * new Rational(1,2).denom
-> 1 * 3 < 2 * 2
-> true
Class hierarchies
类的层级
···
abstract class TopLevel { // abstract class
def method1(x: Int): Int // abstract method
def method2(x: Int): Int = { ... }
}
class Level1 extends TopLevel {
def method1(x: Int): Int = { ... }
override def method2(x: Int): Int = { ...} // TopLevel's method2 needs to be explicitly overridden
}
object MyObject extends TopLevel { ... } // defines a singleton object. No other instance can be created
···
To create an runnable application in Scala:
创建一个可执行的Scala应用
```
object Hello {
def main(args: Array[String]) = println("Hello world")
}
```
or
```
object Hello extends App {
println("Hello World")
}
```
Class Organization
·Classes and objects are organized in packages (package myPackage).
类和对象包括在包中。
·They can be referenced through import statements(import myPackage.MyClass, importmyPackage._, import myPackage.{MyClass1,MyClass2}, import myPackage.{MyClass1=>A})
他们可以通过import 来引用,引用格式如(import myPackage.MyClass, importmyPackage._, 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)
他们也可以在代码中通过全名(new myPackage.MyClass1)来引用
·All members of packages scala and java.lang as well as all members of the object scala.Predef are automatically imported
在scala包和java.lang包中的对象以及scala.Predef包中的对象都会被自动引用
·Traits are similar to Java interfaces, except they can have non-abstract members:trait Planar{...}class Square extends Shape with Planer
特性(traits)与java中的接口类似,但是可以有非抽象的成员:可以这样使用:trait Planar{...}class Square extends Shape with Planer
·General object hierarchy:
通用对象层级:
-scala.Any base type fo all types,Has methods hashCode and toString that can be overriden
-scala.Any 是所有类的基类,方法hashCode和toString 应该被重写
--scala.AnyVal base type of all primitive types.(scala.Double, scala.Float, etc)
--scala.AnyVal 是所有私有基础类型的基类(如scala.Double,scala.Float)
-scala.AnyRef base type of all reference types.(alias of java.lang.Object, supertype of java.lang.String, scala.List, any user-defined class)
-scalaAnyRef 是所有引用类型的基类(是java.lang.Object类的别名, supertype of java.lang.String, scala.List, any user-defined 类等)
-scaka.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.
-scaka.NUll 是scala.Any的子类(null 是Null类型的唯一实例),scala.Nothing是所有其他没有没有实例类型的子类
Type Parameters
类型参数
Similar to C++ templates or Java generics. These can apply to classes, traits or functions.
与C++中的模板或java中的泛型类似,他们可以被应用到类、特性或函数中。
```
class MyClass[T](arg1: T) { ... }
new MyClass[Int](1)
new MyClass(1) // the type is being inferred, i.e. determined based on the value arguments 类型是根据值参数的类型被推断
```
It is possible to restrict the type being used, e.g.
可以限制使用的类型,如:
```
def myFct[T <: TopLevel](arg: T): T = { ... } // T must derive from TopLevel or be TopLevel T是TopLevel的子类或者是TopLevel类
def myFct[T >: Level1](arg: T): T = { ... } // T must be a supertype of Level1 类T是Level的父类
def myFct[T >: Level1 <: Top Level](arg: T): T = { ... }
```
Variance
变型
Given A <: B
If C[A] <: C[B], C is covariant
If C[A] >: C[B], C is contravariant
Otherwise C is nonvariant
已知 A是B的子类 如果C[A]是C[B]的子类,那么C是协变的,如果C[A]是C[B]的父类,那么C是逆变的,否则C是不变的
```
class C[+A] { ... } // C is covariant 协变
class C[-A] { ... } // C is contravariant 逆变
class C[A] { ... } // C is nonvariant 不变
```
For a function, if A2 <: A1 and B1 <: B2, then A1 => B1 <: A2 => B2.
对于一个函数来说如果A2是A1的子类,并且B1是B2的子类,那么以A1为输入参数类型,B1为返回值类型的函数是以A2为输入参数类型,B2为返回值类型的函数的子类。
Functions must be contravariant in their argument types and covariant in their result types, e.g.
要求函数的参数类型符合逆变,返回值符合协变,例如:
```
trait Function1[-T, +U] {
def apply(x: T): U
} // Variance check is OK because T is contravariant and U is covariant
class Array[+T] {
def update(x: T)
} // variance checks fails
```
if A<:B . then everything one can to do with a value of type B one should alse be able to do with a value of type A
=>Let q(x) be a property provable about objects x of type B.Then q(y) should be provable for objects y of type A where A<:B.
Pattern Matching
模式匹配
Pattern matching is used for decomposing data structures:
模式匹配用于分解数据结构
```
unknownObject match {
case MyClass(n) => ...
case MyClass2(a, b) => ...
}
```
Here are a few example patterns
一下是一些例子
```
(someList: List[T]) match {
case Nil => ... // empty list 匹配空列表
case x :: Nil => ... // list with only one element 匹配只有一个元素的列表
case List(x) => ... // same as above 同上
case x :: xs => ... // a list with at least one element. x is bound to the head, 匹配头部至少有一个元素为x的列表
// xs to the tail. xs could be Nil or some other list. ’xs'在末尾,xs可以是空或者其他列表
case 1 :: 2 :: cs => ... // lists that starts with 1 and then 2 匹配列表开头为1,2 的列表
case (x, y) :: ps => ... // a list where the head element is a pair 匹配开头为一个元组的列表
case _ => ... // default case if none of the above matches 匹配其余情况
}
```
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.
最后一个例子说明每个模式都由子模式构成,他只匹配至少具有一个元素的列表,x和y只能匹配特定的类型
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:
模式匹配也可以被用来选择值,一些函数(如Map的get方法)返回值的类型是一个类型为T的可选值的容器,如果值存在Option[T]就是Some[T],否则就是None
```
val myMap = Map("a" -> 42, "b" -> 43)
def getMapValue(s: String): String = {
myMap get s match {
case Some(nb) => "Value found: " + nb
case None => "No value found"
}
}
getMapValue("a") // "Value found: 42"
getMapValue("c") // "No value found"
```
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:
大多数时候,当你在可选值上编写模式匹配时,可以使用Option类的组合方法,getMapValue方法可以写为:
```
def getMapValue(s: String): String =
myMap.get(s).map("Value found: " + _).getOrElse("No value found")
```
Pattern Matching in Anonymous Functions
模式匹配在匿名函数中的应用
Pattern matches are also used quite often in anonymous functions:
模式匹配在匿名函数中也常常被使用
```
val pairs: List[(Char, Int)] = ('a', 2) :: ('b', 3) :: Nil
val chars: List[Char] = pairs.map(p => p match {
case (ch, num) => ch
})
```
Instead of p => p match { case ... }, you can simply write {case ...}, so the above example becomes more concise:
可以用{case ...}而不是使用 p=>p match {case...},那么上面的例子可以写为
```
val chars: List[Char] = pairs map {
case (ch, num) => ch
}
```
Collections
集合
Scala defines several collection classes:
scala定义了很多集合类
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
```
val fruitList = List("apples", "oranges", "pears")
// Alternative syntax for lists
val fruit = "apples" :: ("oranges" :: ("pears" :: Nil)) // parens optional, :: is right-associative
fruit.head // "apples"
fruit.tail // List("oranges", "pears")
val empty = List()
val empty = Nil
val nums = Vector("louis", "frank", "hiromi")
nums(1) // element at index 1, returns "frank", complexity O(log(n))
nums.updated(2, "helena") // new vector with a different string at index 2, complexity O(log(n))
val fruitSet = Set("apple", "banana", "pear", "banana")
fruitSet.size // returns 3: there are no duplicates, only one banana
val r: Range = 1 until 5 // 1, 2, 3, 4
val s: Range = 1 to 5 // 1, 2, 3, 4, 5
1 to 10 by 3 // 1, 4, 7, 10
6 to 1 by -2 // 6, 4, 2
val s = (1 to 6).toSet
s map (_ + 2) // adds 2 to each element of the set
val s = "Hello World"
s filter (c => c.isUpper) // returns "HW"; strings can be treated as Seq[Char]
// Operations on sequences
val xs = List(...)
xs.length // number of elements, complexity O(n)
xs.last // last element (exception if xs is empty), complexity O(n)
xs.init // all elements of xs but the last (exception if xs is empty), complexity O(n)
xs take n // first n elements of xs
xs drop n // the rest of the collection after taking n elements
xs(n) // the nth element of xs, complexity O(n)
xs ++ ys // concatenation, complexity O(n)
xs.reverse // reverse the order, complexity O(n)
xs updated(n, x) // same list than xs, except at index n where it contains x, complexity O(n)
xs indexOf x // the index of the first element equal to x (-1 otherwise)
xs contains x // same as xs indexOf x >= 0
xs filter p // returns a list of the elements that satisfy the predicate p
xs filterNot p // filter with negated p
xs partition p // same as (xs filter p, xs filterNot p)
xs takeWhile p // the longest prefix consisting of elements that satisfy p
xs dropWhile p // the remainder of the list after any leading element satisfying p have been removed
xs span p // same as (xs takeWhile p, xs dropWhile p)
List(x1, ..., xn) reduceLeft op // (...(x1 op x2) op x3) op ...) op xn
List(x1, ..., xn).foldLeft(z)(op) // (...( z op x1) op x2) op ...) op xn
List(x1, ..., xn) reduceRight op // x1 op (... (x{n-1} op xn) ...)
List(x1, ..., xn).foldRight(z)(op) // x1 op (... ( xn op z) ...)
xs exists p // true if there is at least one element for which predicate p is true
xs forall p // true if p(x) is true for all elements
xs zip ys // returns a list of pairs which groups elements with same index together
xs unzip // opposite of zip: returns a pair of two lists
xs.flatMap f // applies the function to all elements and concatenates the result
xs.sum // sum of elements of the numeric collection
xs.product // product of elements of the numeric collection
xs.max // maximum of collection
xs.min // minimum of collection
xs.flatten // flattens a collection of collection into a single-level collection
xs groupBy f // returns a map which points to a list of elements
xs distinct // sequence of distinct entries (removes duplicates)
x +: xs // creates a new collection with leading element x
xs :+ x // creates a new collection with trailing element x
// Operations on maps
val myMap = Map("I" -> 1, "V" -> 5, "X" -> 10) // create a map
myMap("I") // => 1
myMap("A") // => java.util.NoSuchElementException
myMap get "A" // => None
myMap get "I" // => Some(1)
myMap.updated("V", 15) // returns a new map where "V" maps to 15 (entry is updated)
// if the key ("V" here) does not exist, a new entry is added
// Operations on Streams
val xs = Stream(1, 2, 3)
val xs = Stream.cons(1, Stream.cons(2, Stream.cons(3, Stream.empty))) // same as above
(1 to 1000).toStream // => Stream(1, ?)
x #:: xs // Same as Stream.cons(x, xs)
// In the Stream's cons operator, the second parameter (the tail)
// is defined as a "call by name" parameter.
// Note that x::xs always produces a List
```
Pairs (similar for larger Tuples)
```
val pair = ("answer", 42) // type: (String, Int)
val (label, value) = pair // label = "answer", value = 42
pair._1 // "answer"
pair._2 // 42
```
For-Comprehensions
为了方便理解
A for-comprehension is syntactic sugar for map, flatMap and filter operations on collections.
The general form is for (s) yield e
一个为了方便理解Map flatmap filter 等对于集合操作的语法糖,通常的格式如for(s) yield e
- s is a sequence of generators and filters
- s 是一个生成器和过滤器的序列
- p <- e is a generator
- p<-e 是一个生成器
- if f is a filter
- 如果f是一个过滤器
- 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
- 你可以使用{s}而不是(s)如果你希望在其中编写多行,而不使用分号
- e is an element of the resulting collection
- e 是结果集中的一个元素
```
// list all combinations of numbers x and y where x is drawn from
// 1 to M and y is drawn from 1 to N
for (x <- 1 to M; y <- 1 to N)
yield (x,y)
```
is equivalent to
等价于
```
(1 to M) flatMap (x => (1 to N) map (y => (x, y)))
```
Translation Rules
转换规则
A for-expression looks like a traditional for loop but works differently internally
一个for表达式看起来像是传统的for循环,但是其中的工作方式不尽相同
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.
这意味着你可以根据你的理解选择应用的类型,只要定义了map,flatMap,filter操作
example2:
```
for {
i <- 1 until n
j <- 1 until i
if isPrime(i + j)
} yield (i, j)
```
is equivalent to
等价于
```
for (i <- 1 until n; j <- 1 until i if isPrime(i + j))
yield (i, j)
```
is equivalent to
等价于
```
(1 until n).flatMap(i => (1 until i).filter(j => isPrime(i + j)).map(j => (i, j)))
```