Scala Cheatsheet

Scala Cheatsheet

Language
Contributed by Brendan O’Connor

感谢 Brendan O’Connor,本速查表可以用于快速地查找Scala语法结构。Licensed by Brendan O’Connor under a CC-BY-SA 3.0 license.

变量  
 var x = 5                                                                                             可变变量      
Good val x = 5
Bad x=6
常量
 var x: Double = 5                                                                                     显式类型
函数  
 Good def f(x: Int) = { x*x }
Bad def f(x: Int)   { x*x }
定义函数
潜在风险: 不加“=”号将会是一段返回Unit类型的过程,这将会导致意想不到的错误。
Good def f(x: Any) = println(x)
Bad def f(x) = println(x)
定义函数
语法错误: 每个参数都需要指定类型。
type R = Double 类型别名
 def f(x: R) vs.
def f(x: => R)                                                                
传值调用
传名调用 (惰性参数)
(x:R) => x*x 匿名函数
(1 to 5).map(_*2) vs.
(1 to 5).reduceLeft( _+_ )
匿名函数: 下划线是参数的占位符。
(1 to 5).map( x => x*x ) 匿名函数: 必须命名以后才可以多次使用同一个参数。
 Good (1 to 5).map(2*)
Bad (1 to 5).map(*2)
匿名函数: 绑定中缀方法,明智的做法是2*_
 (1 to 5).map { x => val y=x*2; println(y); y }                                                             匿名函数: 代码块风格,最后一个表达式作为返回值。
 (1 to 5) filter {_%2 == 0} map {_*2}                                                                 匿名函数: 管道风格(或者用圆括号)。
 def compose(g:R=>R, h:R=>R) = (x:R) => g(h(x))
val f = compose({_*2}, {_-1})                  
匿名函数: 要传入多个代码块的话,需要使用花括号。
val zscore = (mean:R, sd:R) => (x:R) => (x-mean)/sd 柯里化, 显然的语法。
def zscore(mean:R, sd:R) = (x:R) => (x-mean)/sd 柯里化, 显然的语法。
 def zscore(mean:R, sd:R)(x:R) = (x-mean)/sd                                                           柯里化,语法糖。然后:)
 val normer = zscore(7, 0.4) _                                                                         需要在尾部加下划线来变成偏函数(只对语法糖版本适用)。
def mapmake[T](g:T=>T)(seq: List[T]) = seq.map(g) 泛型
 5.+(3); 5 + 3
(1 to 5) map (_*2)                                                              
中缀语法糖
def sum(args: Int*) = args.reduceLeft(_+_) 变长参数
 
import scala.collection._ 通配符导入
import scala.collection.Vector
import scala.collection.{Vector, Sequence}
选择性导入
import scala.collection.{Vector => Vec28} 重命名导入
import java.util.{Date => _, _} 导入java.util包里除Date之外的一切。
 package pkg at start of file
package pkg { ... }                                            
声明这是一个包
数据结构  
 (1,2,3)                                                                                               元组字面量 (Tuple3)
var (x,y,z) = (1,2,3) 解构绑定:通过模式匹配来解构元组。
 Badvar x,y,z = (1,2,3)                                           潜在风险:整个元组被赋值给了每一个变量。
var xs = List(1,2,3) 列表 (不可变)。
xs(2) 用括号索引 (slides)
 1 :: List(2,3)                                                                                       Cons(构成)
 1 to 5 等价于 1 until 6
1 to 10 by 2                                                    
Range类型(语法糖)
 () (空括号)                                                                                   Unit类型的唯一成员 (相当于 C/Java 里的void).
控制结构  
if (check) happy else sad 条件
if (check) happy same as
if (check) happy else ()
条件(语法糖)
while (x < 5) { println(x); x += 1} while循环
do { println(x); x += 1} while (x < 5) do while循环
import scala.util.control.Breaks._
breakable {
for (x <- xs) {
if (Math.random < 0.1) break
}
}
break. (slides)
 for (x <- xs if x%2 == 0) yield x*10 等价于
xs.filter(_%2 == 0).map(_*10)                  
for 表达式: filter/map
 for ((x,y) <- xs zip ys) yield x*y 等价于
(xs zip ys) map { case (x,y) => x*y }            
for 表达式: 解构绑定
for (x <- xs; y <- ys) yield x*y 等价于
xs flatMap {x => ys map {y => x*y}}
for 表达式: 叉乘
 for (x <- xs; y <- ys) {
   println("%d/%d = %.1f".format(x, y, x/y.toFloat))
}                    
for 表达式: 不可避免的格式
sprintf-style
for (i <- 1 to 5) {
println(i)
}
for 表达式: 包括上边界的遍历
for (i <- 1 until 5) {
println(i)
}
for 表达式: 忽略上边界的遍历
模式匹配  
 Good (xs zip ys) map { case (x,y) => x*y }
Bad (xs zip ys) map( (x,y) => x*y )
在函数的参数中使用模式匹配的例子。
Bad
val v42 = 42
Some(3) match {
case Some(v42) => println("42")
case _ => println("Not 42")
}
“v42” 被解释为可以匹配任何Int类型值的名称,打印输出”42”。
 Good
val v42 = 42
Some(3) match {
  case Some(`v42`) => println("42")
case _ => println("Not 42")
}
有反引号的 “`v42`” 被解释为已经存在的val v42,所以输出的是 “Not 42”.
 Good
val UppercaseVal = 42
Some(3) match {
case Some(UppercaseVal) => println("42")
  case _ => println("Not 42")
}
 UppercaseVal 被视作已经存在的 val,而不是一个新的模式变量,因为它是以大写字母开头的,所以UppercaseVal 所包含的值(42)和检查的值(3)不匹配,输出”Not 42”。
面向对象  
class C(x: R) same as
class C(private val x: R)
var c = new C(4)
构造器参数 - 私有
class C(val x: R)
var c = new C(4)
c.x
构造器参数 - 公有
 class C(var x: R) {
assert(x > 0, "positive please")
var y = x
val readonly = 5
private var secret = 1
def this = this(42)
}

构造函数就是类的主体
声明一个公有成员变量
声明一个可get但不可set的成员变量
声明一个私有变量
可选构造器
new{ ... } 匿名类
abstract class D { ... } 定义一个抽象类。(不可创建)
class C extends D { ... } 定义一个继承子类。
class D(var x: R)
class C(x: R) extends D(x)
继承与构造器参数(愿望清单: 默认自动传参)
 object O extends D { ... }                                                                           定义一个单例(和模块一样)
 trait T { ... }
class C extends T { ... }
class C extends D with T { ... }                
特质
带有实现的接口,没有构造参数。 mixin-able.
 trait T1; trait T2
class C extends T1 with T2
class C extends D with T1 with T2            
(混入)多个特质
 class C extends D { override def f = ...}                                                           必须声明覆盖该方法。
 new java.io.File("f")                                                                             创建对象。
 Bad new List[Int]
Good List(1,2,3)
类型错误: 抽象类型
相反,习惯上:调用工厂(方法)会自动推测类型
classOf[String] 类字面量
x.isInstanceOf[String] 类型检查 (运行时)
x.asInstanceOf[String] 类型强制转换 (运行时)
x: String 归属 (编译时)
bafrjaplpt-brzh-cnthruuk

Contributors to this page: