layout: reveal
List
// Set/Map & Tuple/Option & Array
Scala最初希望同时运行于Java和.net平台,所以需要尽量保持独立,不要与Java的类库产生太多交集
Scala是一门面向对象+函数式的语言,而函数式语言追求"不可变的数据类型”,而Java的类库都是可变的
Scala的类型系统与Java不同
scala.collection.immutable
scala.collection.mutable
package object scala {
type List[+A] = scala.collection.immutable.List[A]
val List = scala.collection.immutable.List
val Nil = scala.collection.immutable.Nil
type ::[A] = scala.collection.immutable.::[A]
val :: = scala.collection.immutable.::
}
* * *
## List api快速浏览
* * *
## 创建普通List:
val list = List("aaa","bbb","ccc")
val list2 = List(1,2,3,4,5,6,7)
* * *
其它方式:
List.range(1, 5) // List(1,2,3,4,5)
(1 to 5).toList // List(1,2,3,4,5)
List.fill(5)('a') // List('a', 'a', 'a', 'a', 'a')
* * *
## 创建空List:
val list = List()
val list = List[String]()
val list2 = List.empty[String]
Nil
* * *
## 基本操作
val list = List(1,2,3,4)
list.head // 1
list.headOption // Some(1)
list.tail // List(2,3,4)
list.init // List(1,2,3)
list.last // 4
list.lastOption // Some(4)
list(0) // 1
list.apply(0) // 1
list.length // 4
list.size // 4
list.isEmpty // false
list.reverse // List(4,3,2,1)
* * *
## 更多操作
val list = List(5,6,7,8)
list.drop(2) // List(7,8)
list.take(3) // List(5,6,7)
list.splitAt(2) // (List(5,6),List(7,8))
list.indices // Range(0, 1, 2, 3)
list.takeWhile (_ < 7) // List(5,6)
list.dropWhile (_%2==1) // List(6, 7,8)
* * *
1 :: List(2,3,4)
1 :: 2 :: 3 :: 4 :: Nil
List(1,2,3) :+ 4
List(1,2) ::: List(3,4)
List(1,2,3).mkString(",") // 1,2,3
List(1,2,3).mkString("[",",","]") // [1,2,3]
* * *
List(5,6,7).zip(List(0,1,2)) // List((5,0), (6,1), (7,2))
List((5,0), (6,1), (7,2)).unzip // (List(5, 6, 7),List(0, 1, 2))
List(5,6,7).zipWithIndex // List((5,0), (6,1), (7,2))
* * *
List(1, 2, 3) map (_ + 1)
List(1, 2, 3) map (x => x + 1)
List(1,2,3).map(x => List(x,x)) // List(List(1,1), List(2,2), List(3,3))
List(List(5,6), List(7,8)).flatten() // List(5,6,7,8)
List(1,2,3).map(x => List(x,x)).flatten // List(1,1,2,2,3,3)
List(1,2,3).flatMap(x => List(x,x)) // List(1,1,2,2,3,3)
* * *
List(1,2,3) foreach { num => println("Num is: " + num) }
List(1, 2, 3, 4, 5) filter (_ % 2 == 0) // List(2, 4)
List(1, 2, 3, 4, 5) partition (_ % 2 == 0) // (List(2, 4),List(1, 3, 5))
List(1,2,3,4,5) find (_%2==0) // Some(2)
List(1, 2, 3, 4, 5) find (_ <= 0) // None
List(1, 2, 3, -4, 5) span (_ > 0) // (List(1, 2, 3),List(-4, 5))
List(1,2,3,4,5,6).groupBy(_ % 3) // Map(2 -> List(2, 5), 1 -> List(1, 4), 0 -> List(3, 6))
List(1,2,3,4,5).grouped(2).toList // List(List(1, 2), List(3, 4), List(5))
* * *
List(1,2,3).forall(_>0) // true
List(1,2,3).exists(_<0) // false
List(1,2,3).foldLeft(10)(_+_) // 16
(10 /: List(1,2,3))(_+_) // 16
List(1,2,3).foldRight(10)(_+_) // 16
(List(1,2,3) :\ 10)(_+_) // 16
"abcde" sortWith (_ > _) // edcba
* * *
## 问题1: 看懂创建List
* * *
### val list = List(“aaa","bbb","ccc")
* * *
等价于
val list = List.apply("aaa","bbb","ccc")
所以`List`是一个`object`
* * *
### List可能是一个单独的`object`:
object List {
def apply[T](items: T*) = ???
}
* * *
### 或者是一个`case class`
(编译器将会生成一个`object`)
case class List[T](items: T*)
* * *
case class List[T](items: T*)
等价于:
class List[T](items: T*)
object List {
def apply[T](items: T*) = ???
}
* * *
## Scala用的是哪一种?
object List {
def apply[T](items: T*) = ???
}
因为它需要定义很多帮助方法,并且还有一个对应的`trait List`
* * *
## 问题2: 关于List类型的推断
* * *
## List[String]
val list = List("aaa","bbb","ccc")
* * *
## List[Int]
val list2 = List(111,222,333)
* * *
## List[Any]
val list3 = List(111,"bbb")
* * *
## 指定类型
val list = List.empty[String]
// List[String]
* * *
## 它的类型呢?
val list4 = List()
* * *
## List[Nothing]
val list1 = List.empty
val list2 = List()
* * *
## `Nil`,等价于`List()`
其定义为:
object Nil extends List[Nothing]
* * *
### 它们可以赋给任意类型的List:
val list:List[String] = List.empty
val list2:List[Int] = Nil
* * *
## 为什么可以赋值?
Nothing
是任意类型的子类型
List[T]
是协变的 (List[+T]
)
List[+T]
,其中的+
表示List
相对于T
是协变的
对于协变的List[+T]
,当C
是P
的子类型时,则List[C]
是List[P]
的子类型。
由子类型定义(是什么?)得知:需要List[P]
的地方,我们总是可以用List[C]
的实例代替
List[String]
的实例赋给List[Any]
List[Nothing]
的实例赋给任意的List[T]
通常不可变的泛型,都可以声明为协变的(这里不讲)
需求:
val bigList = (1 to 1000000).toList
向尾巴依次添加从1到1000这些数
直接在尾巴添加:
(1 to 1000).foldLeft(bigList) {
case (list, item) => list :+ item
}
共用时15349ms
(1 to 1000).foldLeft(bigList.reverse) {
case (list, item) => item :: list
}.reverse
共用时47ms
bigList.foldRight(List.range(1,1001)) {
case (item, list) => item :: list
}
共用时89ms
为什么从前面加效率很高,从后面加效率很低?
(请下节课用代码、图解等方式,为大家讲解这个问题)
class List[T](head:T, tail: List[T])
使用List
:
val list = List(1,2,3)
list match {
case List(a,b,c) => println(s”${a} ~ ${b} ~ ${c}“)
}
//{1} ~ {2} ~ {3}
::
val list = List(1,2,3)
list match {
case head :: tail => println(s"${head} ~ ${tail}")
case _ =>
}
// 1 ~ List(2, 3)
val List(a, b, c) = List(1,2,3)
// a==1, b==2, c==3
::
val ::(a, tail) = List(1,2,3)
// a==1, tail==List(2,3)
val a :: tail = List(1,2,3)
// a==1, tail==List(2,3)
::
?case class Hello(a:String, b:String)
Hello(“aaa”, “bbb”) match {
case Hello(a,b) => println(a + “: " + b)
}
// aaa: bbb
Hello(“aaa”, “bbb”) match {
case a Hello b => println(a + “: " + b)
}
// aaa: bbb
(把这里的Hello
替换为::
即可)
trait Hello[A,B]
def world: Hello[String, Int] = ???
// world: Hello[String,Int]
def anotherWorld: String Hello Int = ???
// anotherWorld: Hello[String,Int]
(跟pattern matching无关)
object Hello {
def unapply(s:String):Option[(String, String)] = ???
}
“hello” match {
case a Hello b => println(a + “: " + b)
}
object Hello {
def unapply(s:String):Option[(String, String, String)] = ???
}
“hello” match {
case a Hello (b,c) => println(a + “: " + b + “: " + c)
}
通常用作中缀的objec名称,都是操作符,比如::
, ~>
::
val list = 1 :: 2 :: 3 :: Nil
list match {
case a :: b :: Nil =>
}
list match {
case ::(a, b) =>
}
::
是不是同一个::
?1 :: 2 :: 3 :: Nil
定义:
abstract class List[+A] {
def ::[B >: A] (x: B): List[B] =
new scala.collection.immutable.::(x, this)
}
1 :: (2 :: (3 :: Nil))
Nil.::(3).::(2).::(1)
case a :: b :: Nil =>
case ::(a, b) =>
定义:
final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extends List[B] { … }
List(1,2) match {
case a :: b :: Nil =>
case a :: b =>
case ::(a, b) =>
}
List(1,2,3) match {
case a :: b :: Nil =>
case a :: b =>
case ::(a, b) =>
}
a :: b == :: (a, b)
a :: b :: Nil == :: (a, ::(b, Nil))
val List(a, tail) = List(1,2,3)
case class User(name:String, friends: Seq[String])
user match {
case User(n, fs) =>
}
// 这里fs一定是Seq[String]类型
object Hello {
def unapply(s:String): Option[(String, List[String])] = ???
}
“some-words” match {
case Hello(a,b) =>
}
// b 一定是 List[String]
val List(a, tail) = List(1,2,3)
// 将会调用
List.unapplySeq(List(1,2,3))
// 并根据其返回值类型与List(a,tail)匹配
// unapplySeq定义
def unapplySeq[A](x: Seq[A]): Option[Seq[A]] = Some(x)
// 其返回值中包含的还是Seq[A]
线索似乎断了~
scala规范中规定了,对于
def unapplySeq(…):Option[Seq[A]]
匹配有两种规则: