notes for TOUR OF SCALA/efficient scala/programming in scala(scala always to be continue)
official website https://docs.scala-lang.org/tour/variances.html
all codes for testing : https://github.com/yuqingwang15/scala-coding
some snippets: http://www.cnblogs.com/yumanman/p/7612689.html
----------
访问object、class、trait内部
将 object、class、trait作为参数
返回object、class、trait
----------
compilation units: Int
, Float
, Array
or Option
----------
package {type member / value member}
tyep member{class/trait}
vlaue{object /def}
----------
class{type/value/shadowed implict/instance contructors}
trait{abstract def / concrete def}
object{value}
----------
class extends class
object extends class
trait extends class
----------
class: abstract , sealed ,case ,
----------
- def的parameters必须属于一种type。
- object B extends Cwith t,因此object不能被extends,若需要使用内部成员,可1import--即为引入,对象可为具有access权限的任何(class,method,object,trait...)2implicit convert 如 implicit def xtoy(x:X.type) = Y3将该成员取出放入一个trait中
- !!!:object o extends C with t{}
- declares an anonymous (inaccessible) class that extends both
B
andC
, and - creates a single instance of this class named
A
. - This means
A
can be passed to functions expecting objects of typeB
orC
, and methodf
can be called usingA.f(...)
.
- declares an anonymous (inaccessible) class that extends both
- trait /object 不能有参数, extends /abstract 区别了trait和class
----------
1 class classname(parameters){...}
- (parameters)
如果不写var/val,则视为private classobjectname.parameters,其他类实例访问无法编译成功。(private 见link)
class Calculator(brand: String) class ScientificCalculator(brand: String) extends Calculator(brand)
如果赋初始值,那么new时传参可有可无。否则必须有相同个数类型的参数传入才能够construct成功。
- private var
同名object与class通信即companion, class中import之后,可访问object值。
同名object中new class可访问class中private值。
class自身通过def funcname 来访问私有成员。
2 method&function
- 可匿名
- var a = ()=>4 a被implicit看做指向function的指针。a()返回function返回值,a返回function自身。
- res0: () => Int = $$Lambda$1000/1271084832@2dd0f797 func为一个object有一个Int值
- 参数为空也是有参数。参数不需var/val
- 函数即对象:函数是一些特质的集合。具体来说,具有一个参数的函数是Function1特质的一个实例。这个特征定义了
apply()
语法糖,让你调用一个对象时就像你在调用一个函数。 - object addOne extends Function1[Int, Int] { def apply(m: Int): Int = m + 1 } >addOne(1) res2: Int = 2
- 这个Function特质集合下标从0开始一直到22。为什么是22?这是一个主观的魔幻数字(magic number)。我从来没有使用过多于22个参数的函数,所以这个数字似乎是合理的。
- apply语法糖有助于统一对象和函数式编程的二重性。你可以传递类,并把它们当做函数使用,而函数本质上是类的实例。
- !!:class extends class,object也可以extends class。object可以像函数被用,函数和object都可以是traits的集合。trait里可有abstract def可有concrete def,trait同样可以被new。
3 class
- 通过参数是否有var 表明private or public constructor
- Parameters without
val
orvar
are private values, visible only within the class. constructor - classa(var str:String) ,extends时str 需要指明
- one superclass but many mixins extends。可以将trait和class组合成一个新class,像多个def 组合在一个def里。
- 当class or trait有sealed标记时 we don’t need a “catch all” case
4 traits
- 在trait中def hasNext:Boolean或var hasNext:Boolean override时分别为def hasNext: Boolean = 3<3 val hasNext: Boolean = 3<3 两者完全一样
- Subtypes of traits 有点类似于抽象类的子类
- 什么时候应该使用特质而不是抽象类?
5 case class & pattern matching
- 样本类也可以像普通类那样拥有方法。
- case classes have an
apply
method by default which takes care of object construction.因此“样本类”不需要new - When you create a case class with parameters, the parameters are public
val
s.因此不能再赋值,参数不能有var/val - compared by structure and not by reference 因此即使指向不同的object也会看具体value是否相同
- by using the
copy
method. You can optionally change the constructor arguments.注意是可选参数的shallow copy - In the
case Email(email, _, _) if importantPeopleInfo.contains(email)
, the pattern is matched only if theemail
is in the list of important people.和if <boolean expression>连用,相当于case之下再进行对参数的筛选 - case class在abstract class之下即对abstract的不同继承
- 想要在pattern中call a method,在case是否某一类时最好用class identifier的第一个字母表示 case p:Phone=>p.sendMsg
- match: 有时用参数来match,有时只match a type
- _ 通配 否则当传进一个不能被匹配的数字的时候,你将获得一个运行时错误
6 currying
- When a method is called with a fewer number of parameter lists, then this will yield a function taking the missing parameter lists as its arguments.
7 sealed
- Traits and classes can be marked
sealed
which means all subtypes must be declared in the same file. The assures that all subtypes are known.
8 singleton objects
- 其中的method available globally。因此可以 referred to, or imported
- case class with no type parameters will by default create a singleton object of the same name, with a
Function*
trait implemented. - 伴生不在一起定义时出现warning
- 可继承classes and traits
- companions即类与object同名,需要在一个source file里定义。另 Scaladoc直接可跳转,符号:C与O。我们通常将伴生对象作为工厂使用。
- all members that would be static, including classes, should go in a singleton object.(java中使用的是static)
- 值和函数不能在类或单例对象之外定义。单例对象是组织静态函数(static function)的有效工具。
9 implicit
- A method with implicit parameters can be applied to arguments just like a normal method.
-
implicit values can not be top-level, they have to be members of a template.
- if such a method misses arguments for its implicit parameters, such arguments will be automatically provided.并且 actual arguments for implicit parameters 可分为两类
- 第一类:all identifiers x that can be accessed at the point of the method call without a prefix and that denote an implicit definition or an implicit parameter.即implicitly find在目前scope中有同样type的val或object替代这个参数
- 第二:all members of companion modules of the implicit parameter’s type that are labeled implicit.即implicit parameter’type 的所有companion成员
- static:
10 extractor object
- an object with an
unapply
method(unapply: takes an object and tries to give back the arguments) - case CustomerID(name) => 或 val CustomerID(name) = customer2ID相当于val name = CustomerID.unapply(customer2ID).get
- 即CustomerID("wang")是call apply,CustomerID(name)是call unapply 并且可通过.get得到name 赋值的表达式本质还是match方法
- unapply方法的返回:Boolean或Option[T]或Option[(T1,...,Tn)] 或Option[Seq[T]]
- define patterns through
unapplySeq
which returnsOption[Seq[T]]
This mechanism is used for instance in patterncase List(x1, ..., xn)
.--需要返回的sub-value个数不确定时
11 sequence comprehensions.
for (enumerators) yield e
, whereenumerators
refers to a semicolon-separated list of enumerators- An enumerator is either a generator which introduces new variables, or it is a filter.
12 [T] generic
- take a type as a parameter,useful for collection classes
Stack[A]
is only a subtype ofStack[B]
if and only ifB = A
- 以泛型作参
-
trait Cache[K, V] { def get(key: K): V def put(key: K, value: V) def delete(key: K) } def remove[K](key: K)//方法中以泛型作参
13 +A -A A variance
- +A where
A
is a subtype ofB
, thenList[A]
is a subtype ofList[B]
- -A where
A
is a subtype ofB
,Writer[B]
is a subtype ofWriter[A]
. - trait Function1[-T, +R] T:argument type R:return type
-
需要注意的是,所有的类型信息会在编译时被删去,因为它已不再需要。这就是所谓的擦除。学术界一直很努力地提高类型系统的表现力,包括值依赖(value-dependent)类型!用程序将会退化为一系列类型转换(“asInstanceOf[]”),并且会缺乏类型安全的保障(因为这些都是动态的)。
-
在函数式编程语言中,类型推断的经典方法是 Hindley Milner算法,它最早是实现在ML中的。Scala类型推断系统的实现稍有不同,但本质类似:推断约束,并试图统一类型
- 有一些你想表达的类型概念“过于泛化”以至于编译器无法理解
-
- An upper type bound
T <: A
declares that type variableT
refers to a subtype of typeA
14 你并不关心是否能够命名一个类型变量,可以使用“通配符”取而代之。List[_] 相当于 List[ T forSome { type T } ]
15 The term B >: A
expresses that the type parameter B
or the abstract type B
refer to a supertype of type A
.
def prepend(elem: B) = ListNode[B](elem, this)
16
17
18 scala类中不带参数的方法和属性可以互相重写。
19 尾递归函数:指的是递归函数的递归语句在函数的最后一行,这种递归函数的执行速度和使用循环代替递归的速度是一样的,不会有任何额外开销。
20 import 可以重命名或者隐藏一些被引用的成员。
//只能访问ArrayBuffer 的 concat和newBuilder两个方法,其他方法被隐藏,并且给 concat加了个别名conc,你可以通过conc访问concat import scala.collection.mutable.ArrayBuffer.{concat =>conc,newBuilder} //可以访问除了newBuilder 外的所有成员 import scala.collection.mutable.ArrayBuffer.{newBuilder =>_,_}
21 scala三引号的作用和python三引号的作用相同
22 嵌套类 若需要被嵌套的类的实例之间可沟通,需要在类中所需沟通用到的被嵌套类表示为:类名#被嵌套类名
23 插值:f s raw
24 : 右结合
object Log { def >>:(data:String):Log.type = { println(data); Log } }
res0: "Hadoop" >>: "Spark" >>: Log
25 abstract class
- Traits and abstract classes can have an abstract type member.
26 exception
- 面向表达式
- 当一个异常被捕获处理了,finally块将被调用;它不是表达式的一部分。
27 Set & List & Tuple & Map & Option
-
val numbers = List(1, 2, 3, 4)
-
scala> Set(1, 1, 2) res0: scala.collection.immutable.Set[Int] = Set(1, 2)
- 元组是在不使用类的前提下,将元素组合起来形成简单的逻辑集合。元组不能通过名称获取字段,而是使用位置下标来读取对象;而且这个下标基于1,而不是基于0。
-
映射的值可以是映射或是函数
-
Option本身是泛型的,并且有两个子类:
Some[T]
或None。
Map.get
使用Option
作为其返回值,表示这个方法也许不会返回你请求的值。 如Map("one"->1).get("one"),这里返回 res0: Option[Int] = Some(1),为option的子类,若需要取值则get、getOrElse 用法见snippets。
28 Functional Combinators
-
List(1, 2, 3) map squared。foreach
很像map,但没有返回值。foreach仅用于有副作用[side-effects]的函数。 -
map
对列表中的每个元素应用一个函数或传入一个部分应用函数(和_结合使用)。Map可以被看作是一个二元组的列表,所以你写的函数要处理一个键和值的二元组。 filter
移除任何对传入函数计算结果为false的元素。返回一个布尔值的函数通常被称为谓词函数[或判定函数]。zip
将两个列表的内容聚合到一个对偶列表中。partition
将使用给定的谓词函数分割列表。find
返回集合中第一个匹配谓词函数的元素。drop
将删除前i个元素dropWhile
将删除元素直到找到第一个匹配谓词函数的元素。例如,如果我们在List(1,2,3)上使用dropWhile
奇数的函数,1
将被丢弃(但3
不会被丢弃,因为他被2
“保护”了)。- fold 见link
flatten
将嵌套结构扁平化为一个层次的集合。可以把flatMap看做是“先映射后扁平化”的快捷操作
29 compose & andThen
-
val fComposeG = f _ compose g _ : f(g(x))
-
val fAndThenG = f _ andThen g _ : g(f(x))
30 PartialFunction
-
一个定义为
(Int) => String
的偏函数可能不能接受所有Int值为输入。isDefinedAt
是PartialFunction的一个方法,用来确定PartialFunction是否能接受一个给定的参数。 - 偏函数
PartialFunction
和我们前面提到的部分应用函数是无关的。 - case是PF函数的子类
- 可以使用
orElse
组成新的函数,得到的PartialFunction反映了是否对给定参数进行了定义。