scala 学习笔记-持续更新中

学习列表:

  1. scala官方文档
  2. scala cheat
  3. twitter Scala 课堂
  4. 有趣的 Scala 语言: 使用递归的方式去思考
  • 几乎一切乎都是表达式
scala> 1 + 1
res0: Int = 2
  • 复合表达式——{}

花括号用于创建复合表达式,复合表达式的返回值是最后一个表达式

scala> {
     | println("hello world")
     | "hi"
     | }
hello world
res0: String = hi
  • 常量

使用val,不能重复给常量赋值

scala> val value = 100 + 1
value: Int = 101
scala> value = 200// 给常量重复赋值将报错
<console>:11: error: reassignment to val
       value = 200
             ^
  • 变量

使用var,可以修改变量的值

scala> var value = 100
value: Int = 100
scala> value = 200
value: Int = 200
  • 类型推断

scala支持类型推断,类型声明置后,编译器会推断其类型,会比java更加简洁

scala> val m: Int = 100// 不建议
m: Int = 100
scala> var n: String = "hi"// 不建议
n: String = hi
scala> val m = 100// 推荐
m: Int = 100
scala> var n = "hi"// 推荐
n: String = hi
  • 函数

使用def创建函数(与python一样),需要为函数参数指定类型签名,函数返回值类型可以不写(递归函数必须声明返回值类型),让编译器进行类型推断

scala> def sum(a: Int, b: Int): Int = a + b// 中规中矩的写法
sum: (a: Int, b: Int)Int
scala> sum(2, 3)
res8: Int = 5
scala> def fun(x: Int) = x*x// 不声明返回值类型
fun: (x: Int)Int
scala> fun(5)
res9: Int = 25
// 使用复合表达式
scala> def mul(x: Int, y: Int) = {
     | println(x.toString)
     | println(y.toString)
     | x * y
     | }
mul: (x: Int, y: Int)Int
scala> mul(2, 3)
2
3
res12: Int = 6
// 无返回值的函数可以不用=,代表返回值为Unit类似java中void
scala> def hi() {
     | println("hi world!")
     | }
hi: ()Unit
scala> hi// 无参函数可以不使用括号调用
hi world!
  • 匿名函数

使用 =>

scala> (x: Int) => x*x
res14: Int => Int = <function1>
scala> res14(5)
res15: Int = 25

可以将匿名函数进行赋值

scala> val fun = (x: Int) => x*x
fun: Int => Int = <function1>
scala> fun(3)
res27: Int = 9

同样可以使用{}定义复杂的匿名函数

scala> var m = {x: Int =>
     | println("hi")
     | val temp = x*x
     | temp + 1
     | }
m: Int => Int = <function1>
scala> m(4)
hi
res28: Int = 17
  • 部分应用(partially applied function)

你可以使用下划线“_”(通配符)部分应用一个函数,结果将得到另一个函数。

scala> def add(x: Int, y: Int) = x+y
add: (x: Int, y: Int)Int
scala> add(4, _:Int)
res1: Int => Int = <function1>
scala> res1(3)
res2: Int = 7
  • 柯里化函数(curried)

有时会有这样的需求:允许别人一会在你的函数上应用一些参数,然后又应用另外的一些参数。

scala> def mul(x: Int)(y:Int) = x*y
mul: (x: Int)(y: Int)Int
scala> mul(2)_
res3: Int => Int = <function1>
scala> res3(5)
res4: Int = 10

多参函数柯里化

scala> def mul3(x: Int, y: Int, z: Int) = x*y*z
mul3: (x: Int, y: Int, z: Int)Int
scala> (mul3 _).curried
res8: Int => (Int => (Int => Int)) = <function1>
scala> res8(2)
res9: Int => (Int => Int) = <function1>
scala> res9(3)
res10: Int => Int = <function1>
scala> res10(4)
res11: Int = 24
  • 变长参数

向方法传入任意多个同类型的参数,比如任意多个整数求和

scala> def sum(nums: Int*) = (nums reduceLeft ((x: Int, y: Int) => x+y))
sum: (nums: Int*)Int
scala> sum(1,2,3,4,5,6,7,8,9,10)
res19: Int = 55
  • 参数限定

scala可以使用require进行函数参数限制,类似java assert

scala> def sq(x: Int) = {
     | require(x >= 0, "input must > 0!")
     | math.sqrt(x)
     | }
sq: (x: Int)Double
scala> sq(2)
res0: Double = 1.4142135623730951
scala> sq(-1)
java.lang.IllegalArgumentException: requirement failed: input must > 0!
  at scala.Predef$.require(Predef.scala:219)
  at .sq(<console>:11)
  ... 33 elided
  • 隐式参数(implicit)

可以为方法定义隐式的参数值,在不传值的情况下,编译器会从当前作用域自动检索满足类型要求的隐式参数进行填充,但是必须保证无二义性

scala> def func(implicit str: String) = println(str)
def func(implicit str: String): Unit
scala> implicit val x = "test"
val x: String = test
scala> func
test
scala> implicit val y = "yyds"
val y: String = yyds
scala> func // 出现二义性,存在多个满足类型要求的隐式参数
       ^
       error: ambiguous implicit values:
        both value x of type String
        and value y of type String
        match expected type String
  • 隐式类型转换方法(implicit)

当编译器发现方法入参类型不满足要求时,会在当前作用域下自动寻找满足需求的隐式类型转换方法

scala> implicit def fun(x: String) = x.toInt
fun: (x: String)Int
scala> math.max("132", 13)
res0: Int = 132
  • 隐式类(implicit)

支持扩展对象调用自身未定义的方法,编译器发现无该方法时会在当前作用域下自动寻找满足条件的隐式类

scala> class Animal {}
class Animal
scala> implicit class Fly(animal: Animal) {
     | def fly() = println("I can fly")
     | }
class Fly
scala> val animal = new Animal
val animal: Animal = Animal@715fa8c5
scala> animal.fly
I can fly
  • 闭包(closure)

函数及其执行所需的上下文环境(“An object is data with functions. A closure is a function with data.” — John D. Cook)

scala> def fun() = {
     | var i = 0
     | val lam = () => {i+=1;i}
     | lam
     | }
fun: ()() => Int
scala> val clo = fun()
clo: () => Int = <function0>
scala> clo()
res0: Int = 1
scala> clo()
res1: Int = 2
scala> clo()
res2: Int = 3
  • 传名参数(call by name,传值、传引用之外的另外一种参数传递方式)

传名的参数传递使用替换规则。

scala> def callByNameFun(x: => Int) = List(x, x)// =>开头为传名参数
callByNameFun: (x: => Int)List[Int]
// 定义高阶函数createNum产生一个函数,使用闭包,每调用一次fun(),i自增加1
scala> def createNum() = {
     | var i = 0
     | val fun = {
     | () =>
     | i += 1
     | i
     | }
     | fun
     | }
createNum: ()() => Int
scala> val f = createNum()
f: () => Int = <function0>
scala> callByNameFun(f())
res0: List[Int] = List(1, 2)
scala> callByNameFun(f())
res1: List[Int] = List(3, 4)
  • 尾递归

尾递归函数返回值为本身或者结果,同一般的递归相比,可被直接转化为循环,栈的开销为O(1),scala中可以用 @tailrec 检测定义的函数是否为尾递归

scala> import scala.annotation.tailrec
scala> @tailrec def fun(re: Int, index: Int): Int = {
     | if (index == 0) {
     | re
     | } else {
     | fun(re+index, index - 1)
     | }
     | }
fun: (re: Int, index: Int)Int
scala> fun(0, 100)
res0: Int = 5050
scala> fun(0, 100)
res1: Int = 5050

使用class关键字

scala> class User {
     | var name = "bernie"
     | var age = 23
     | def show() = println(name + ":" + age.toString)
     | }
defined class User
scala> var user = new User()
user: User = User@41112c13

构造函数,构造函数不是特殊的方法,他们是除了类的方法定义之外的代码。

scala> class Person(pName: String, pAge: Int) {
     | var name = pName
     | var age = pAge
     | def show() = println(name + ":" + age.toString)
     | }
defined class Person
// 也可重载构造函数
scala> class Person(pName: String, pAge: Int) {
     | def this(pName: String) = this(pName, 18)
     | var name = pName
     | var age = pAge
     | }
defined class Person
  • 抽象类

和java差不多,继承也使用extends

scala> abstract class AbstractFather {
     | def fun(x: Int): Int
     | }
defined class AbstractFather
  • 特质(trait)

是一组属性与行为的组合,特质可以多扩展,在抽象类与特质之间优先选择特质

scala> trait Fly {
     | val wing: Int
     | def fly() = println("I can fly")
     | }
defined trait Fly
scala> trait Run {
     | val leg: Int
     | def run() = println("I can run")
     | }
defined trait Run
scala> class Bird extends Fly with Run {
     | val wing = 2
     | val leg = 2
     | def power() = {
     | fly()
     | run()
     | }
     | }
defined class Bird
scala> new Bird().power()
I can fly
I can run
  • 单例的语言级别实现——object

Util类就非常适合使用object定义

object Util {
    def echo() = println("Hello World!")
}
  • 伴生对象与伴生类

名字相同的class与object,放在同一个文件下定义,能够访问彼此的私有成员

  • 泛型

使用中括号,类和方法都可以是泛型的

scala> class Gen[T] {
     | def show(x: T) = x.toString + "$"
     | }
defined class Gen
scala> val gen = new Gen[Int]
gen: Gen[Int] = Gen@3a44ebcb
scala> gen.show(100)
res11: String = 100$
scala> def genFun[T](x: T) = x.toString + "&"
genFun: [T](x: T)String
scala> genFun(100)
res13: String = 100&
  • 语法糖 apply update

为了方便你使用类,scala提供了apply 与 update语法糖

scala> object Arr {
     | val arr = Array(0,1,2,3,4,5)
     | def apply(i: Int) = arr(i)
     | def update(i: Int, value: Int) = {arr(i) = value}
     | }
defined object Arr
scala> Arr(1)
res38: Int = 1
scala> Arr(1) = 100
scala> Arr.arr
res40: Array[Int] = Array(0, 100, 2, 3, 4, 5)

其实 Array 取值与更新就是实现了这两个方法


scala数组
  • 函数与对象de边界

函数可以看作一堆特性的集合(Funtion0 -> Funtion22),apply语法糖有助于统一对象和函数式编程的二重性,你可以传递类,并把它们当做函数使用,而函数本质上是类的实例

scala> object Fun extends Function1[Int, Int] {
     | def apply(x: Int) = x*x
     | }
defined object Fun
scala> Fun(3)
res50: Int = 9
  • 模式匹配

感觉像java中switch case,但功能更加强大

scala> val m = 1
m: Int = 1
scala> m match {
     | case 1 => 100
     | case 2 => 200
     | case _ => 300
     | }
res25: Int = 100
  • 异常

异常也是表达式

scala> val re = try {
     | 1/0
     | "oh yeah"
     | } catch {
     | case e: Exception => println("error happen")
     | "oh no"
     | } finally {
     | println("turn me")
     | }
error happen
turn me
re: String = oh no
  • 集合
scala集合

Seq(列表)、Set(集)、Tuple(元组)、Map(映射)、Option(选项)

Tuple

元组是在不使用类的前提下,将元素组合起来形成简单的逻辑集合,读取方式使用下标,从1开始,可以使用 "->" 符号创建2元组

scala> val tuple = ("hi", "he", "ha", 12, 'a')
tuple: (String, String, String, Int, Char) = (hi,he,ha,12,a)
scala> tuple._1
res36: String = hi
scala> 1 -> 2
res63: (Int, Int) = (1,2)

Map

scala> Map(1 -> "one", 2 -> "two")
res0: scala.collection.immutable.Map[Int,String] = Map(1 -> one, 2 -> two)
scala> Map((1, "one"), (2, "two"))
res1: scala.collection.immutable.Map[Int,String] = Map(1 -> one, 2 -> two)

Option

表示可能包含值的容器,有Some与None两个子类,特征接口如下

trait Option[T] {
  def isDefined: Boolean
  def get: T
  def getOrElse(t: T): T
}
scala> val map = Map(1 -> "one", 2 -> "two")
map: scala.collection.immutable.Map[Int,String] = Map(1 -> one, 2 -> two)
scala> map.get(1)
res2: Option[String] = Some(one)
scala> map.get(3)
res3: Option[String] = None
scala> res2.get
res4: String = one
scala> res3.get
java.util.NoSuchElementException: None.get
  at scala.None$.get(Option.scala:347)
  at scala.None$.get(Option.scala:345)
  ... 33 elided
scala> res3.isDefined
res6: Boolean = false
scala> res3.getOrElse("three")
res7: String = three
  • 集合操作符(操作符即函数)

map、foreach

map将产生一个新的集合,foreach无返回值,一般仅作遍历使用,取它的副作用

scala> (1 to 10) map (_ * 2)
res21: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
scala> (1 to 10) foreach (println)
1
2
3
4
5
6
7
8
9
10

reduceLeft、reduceRight(将集合进行函数计算,得到结果)

scala> (1 to 10) reduceLeft (_ + _)
res42: Int = 55
scala> (1 to 10) reduceRight (_ + _)
res43: Int = 55

fold
fold 支持自定义初始值的聚合计算

scala> (1 to 10).fold(10)(_ + _)
res10: Int = 65

filter(白名单过滤)、partition(分割)

fliter 将符合条件的元素产生一个集合返回
partition 将其分隔成满足与不满足条件的两元组

scala> (1 to 10) filter (_%2 == 0)
res24: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)
scala> (1 to 10) partition (_%2 == 0)
res25: (scala.collection.immutable.IndexedSeq[Int], scala.collection.immutable.IndexedSeq[Int]) = (Vector(2, 4, 6, 8, 10),Vector(1, 3, 5, 7, 9))
scala> res25._1
res26: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)
scala> res25._2
res27: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 3, 5, 7, 9)

find、exists、forall、count

find 返回符合条件的第一个选项 Option
exists 只要集合中有任意元素符合条件及返回 true,否则 false
forall 需要集合所有元素都满足条件才返回 true,否则 false
count 返回满足条件的元素个数Int

scala> (1 to 10) find (_%2==0)
res30: Option[Int] = Some(2)
scala> (1 to 10) exists (_%2==0)
res40: Boolean = true
scala> (1 to 10) forall (_ > 0)
res50: Boolean = true
scala> (1 to 10) count (_ %2 ==0)
res60: Int = 5

zip

顾名思义就是像拉链一样彼此咬合生成新的集合,长短不一的时候以短为准

scala> Array(1, 2, 3) zip List("a", "b", "c", "d")
res53: Array[(Int, String)] = Array((1,a), (2,b), (3,c))
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 数组是一种可变的、可索引的数据集合。在Scala中用Array[T]的形式来表示Java中的数组形式 T[]。 v...
    时待吾阅读 904评论 0 0
  • FP 3.1.函数 函数的地位和一般的变量是同等的,可以作为函数的参数,可以作为返回值。传入函数的任何输入是只读的...
    时待吾阅读 1,053评论 0 2
  • lang 2.1.和Java的异同 2.1.1.语法 Java++:增加的语法 -》纯OO;操作符重载;closu...
    时待吾阅读 2,319评论 0 0
  • 下划线这个符号几乎贯穿了任何一本Scala编程书籍,并且在不同的场景下具有不同的含义,绕晕了不少初学者。正因如此,...
    Helen_Cat阅读 2,142评论 0 3
  • Scala的集合类可以从三个维度进行切分: 可变与不可变集合(Immutable and mutable coll...
    时待吾阅读 5,706评论 0 4