分享

Scala简明教程

韩克拉玛寒 发表于 2015-3-27 23:21:59 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 11 93642
本帖最后由 韩克拉玛寒 于 2015-3-27 23:21 编辑
问题导读:

1、如何理解Scala语言
2、如何理解Scala函数以及方法?





Scala简明教程

目录 [−]
      变量声明
      函数
      包package
      数据结构
      字符串
      控制流程
      模式匹配
      面向对象
      泛型
      注解
      Implicit
      空对象Nil,Null,null,Unit,Nothing,None


      Scala是一门多范式(multi-paradigm)的编程语言。
      Scala源代码被编译成Java字节码,所以它可以运行于JVM之上,并可以调用现有的Java类库。
洛桑联邦理工学院的Martin Odersky于2001年基于Funnel的工作开始设计Scala。Funnel是把函数式编程思想和佩特里网相结合的一种编程语言。Odersky先前的工作是Generic Java和javac。Java平台的Scala于2003年底/2004年初发布。该语言第二个版本,v2.0,发布于2006年3月。


Scala是面向对象的,比Java更彻底

一切皆为对象, 数值,函数都是对象

全部支持函数式编程
包括函数即是对象,lambda,currying, type inference, immutability, lazy evaluation, and pattern matching

强大的静态类型系统
algebraic data types, covariance and contravariance, higher-order types, anonymous types, generic classes, upper and lower type bounds, inner classes and abstract types as object members, compound types, explicitly typed self references , views and polymorphic methods

其它Java不支持的功能:

operator overloading, optional parameters, named parameters, raw strings, and no checked exceptions

2009年4月,Twitter宣布他们已经把大部分后端程序从Ruby迁移到Scala,其余部分也打算要迁移。这里有一篇文章解释Twitter为什么使用Scala编程语言。
Engineer-to-Engineer Series Programming Languages Programming Languages Scala Talks
Coursera把Scala作为服务器语言使用。Why we love Scala at Coursera
一些Scala学习资料:

Scala documentation
Learning Scala
Effective Scala
Scala School
Scala cheatsheets


大数据生态圈中的Kafka和Spark都是由Scala开发的,这也是我为什么学习Scala的原因之一。
作为一个十多年Java程序员,同时在学习Scala和go这两种语言。 学习的过程中感觉go语言太好学了, 入手很快, 而Scala的语法和类C语言如Java,C#等很不一样, 很多语法的技巧在里面。 基于此,我特地整理了这篇文章。 简单扼要的介绍Scala语言的知识点,尤其是和Java不太一样的地方。

$变量声明
  1. var x = 5
  2. var x:Double = 5
  3. val y = 7
复制代码

var声明变量, val声明常量, 类型可省略, Scala可以推断出数据类型
函数

  1. def f(x: Int) = { x*x }
  2. def f(x: Any): Unit = println(x)
复制代码


定义函数, 返回值类型可省略, =等号后面可以是块定义或者表达式。

  1. reply()
  2. reply
复制代码

无参数的函数调用时可以省略括号。

  1. names foreach (n => println(n))
  2. names mkString ","
  3. optStr getOrElse "<empty>"
复制代码

一个参数时可以使用infix写法
infix操作符可以定义如下:

  1.    class MyBool(x: Boolean) {
  2. def and(that: MyBool): MyBool = if (x) that else this
  3. def or(that: MyBool): MyBool = if (x) this else that
  4. def negate: MyBool = new MyBool(!x)
  5. def not(x: MyBool) = x negate; // semicolon required here
  6. def xor(x: MyBool, y: MyBool) = (x or y) and not(x and y)
  7. }
  8. //更多例子
  9. 5.+(3); 5 + 3
  10. (1 to 5) map (_*2)
  11. def f(x: R)
  12. def f(x: => R)
复制代码

第一个call-by-value ,第二个call-by-name(lazy parameters)

  1. (x:R) => x*x
复制代码


匿名函数(lambda表达式)
=>可以由 &#8658; 字符替代(\u21D2),同样 <-和 ->也可以由单个的字符取代: ← 和 →

  1. (1 to 5).map(_*2)
  2. (1 to 5).reduceLeft( _+_ )
复制代码


下划线代表替代, 更多的下划线功能参看 讨论

  1. (1 to 5).map(2*)
  2. 等价
  3. (1 to 5).map(2* _)
  4. (1 to 5).map { val x=_*2; println(x); x }
  5. (1 to 5) filter {_%2 == 0} map {_*2}
复制代码


匿名函数的块风格实现,最后一个语句作为返回值

  1. def compose(g:R=>R, h:R=>R) = (x:R) => g(h(x))
  2. val f = compose({_*2}, {_-1})
复制代码


多个块作为参数

  1. val zscore = (mean:R, sd:R) => (x:R) => (x-mean)/sd  //currying, obvious syntax.
  2. def zscore(mean:R, sd:R) = (x:R) => (x-mean)/sd  //currying, obvious syntax
  3. def zscore(mean:R, sd:R)(x:R) = (x-mean)/sd       //currying, 语法糖,也叫参数分组. 但是必须按照下面的语法调用:
  4. val normer = zscore(7, 0.4)_         //需要尾部的下划线,仅限于上面一行的语法糖
  5. def sum(args: Int*) = args.reduceLeft(_+_)
复制代码


可变参数
$ 包package


  1. import scala.collection._  //通配符导入,类似java中的.*
  2. import scala.collection.Vector
  3. import scala.collection.{Vector, Sequence}  //导入多个
  4. import scala.collection.{Vector => Vec28}  //别名.
  5. import java.util.{Date => _, _}  //除了Date,其它都导入
  6. package pkg at start of file
  7. package pkg { ... }
复制代码


一般语句后面可以省略 ;
& 数据结构


  1. (1,2,3)
  2. var (x,y,z) = (1,2,3)
复制代码


tuple类型

  1. var xs = List(1,2,3)
  2. xs(2)
复制代码


List类型

  1. 1 :: List(2,3)
  2. List(1, 2) ::: List(2, 3)
  3. List(1, 2) ++ Set(3, 4, 3)
复制代码


一些特殊的操作符


  1. 1 to 5 same as 1 until 6
  2. 1 to 10 by 2
复制代码


range

$ 字符串


  1. val name = "James"
  2. println(s"Hello, $name") // Hello, James
  3. println(s"1 + 1 = ${1 + 1}")
复制代码

s前缀, 替换字符串中的变量或表达式

  1. val height = 1.9d
  2. val name = "James"
  3. println(f"$name%s is $height%2.2f meters tall") // James is 1.90 meters tall
复制代码


f前缀, printf风格的格式化


  1. scala> raw"a\nb"
  2. res1: String = a\nb
复制代码


raw前缀, 原始字符,不转义


  1. scala> "a".r
  2. res1: scala.util.matching.Regex = a
复制代码


r后缀, 正则表达式
  1. implicit class JsonHelper(private val sc: StringContext) extends AnyVal {
  2.   def json(args: Any*): JSONObject = ...
  3. }
  4. val x: JSONObject = json"{ a: $a }"
复制代码


自定义的字符串拦截器
$ 控制流程

  1. if (check) happy else sad
  2. if (check) happy   //下面一样
  3. if (check) happy else ()
复制代码


>> if语句
  1. while (x < 5) { println(x); x += 1}
  2. do { println(x); x += 1} while (x < 5)
复制代码


while语句
  1. import scala.util.control.Breaks._
  2. breakable {
  3.   for (x <- xs) {
  4.     if (Math.random < 0.1) break
  5.   }
  6. }
  7. for (x <- xs if x%2 == 0) yield x*10 //与下面的等价
  8. xs.filter(_%2 == 0).map(_*10)
  9. for ((x,y) <- xs zip ys) yield x*y //与下面的等价
  10. (xs zip ys) map { case (x,y) => x*y }
  11. for (x <- xs; y <- ys) yield x*y  //与下面的等价
  12. xs flatMap {x => ys map {y => x*y}}
  13. for (x <- xs; y <- ys) { //双层嵌套,类似for {for {}}
  14. println("%d/%d = %.1f".format(x,y, x*y))
  15. }
  16. for (i <- 1 to 5) {
  17. println(i)
  18. }
  19. for (i <- 1 until 5) {
  20. println(i)
  21. }
复制代码


$ 模式匹配

  1. (xs zip ys) map { case (x,y) => x*y }
  2. val v42 = 42
  3. Some(3) match {
  4. case Some(`v42`) => println("42")
  5. case _ => println("Not 42")
  6. }
  7. val UppercaseVal = 42
  8. Some(3) match {
  9. case Some(UppercaseVal) => println("42")
  10. case _ => println("Not 42")
  11. }
复制代码


case class自动生成equals和toString,参数相同则==返回true
$ 面向对象
    没有访问修饰符的class或者类成员默认都是public类型的。

  1. class C(x: R) //等价于
  2. class C(private val x: R)
  3. var c = new C(4)
复制代码

>> 参数是private类型

  1. class C(val x: R)
  2. var c = new C(4)
  3. c.x
复制代码


>> 参数是public类型

  1. class C(var x: R) {
  2. assert(x > 0, "positive please") //constructor is class body,所以你可以在这里写一些语句
  3. var y = x  //public成员
  4. val readonly = 5 //只能读取,无法set
  5. private var secret = 1 //private成员
  6. def this = this(42) //其它构造函数
  7. }
  8. new{ ... }
  9. abstract class D { ... }
  10. class C extends D { ... }  //继承
  11. class D(var x: R)
  12. class C(x: R) extends D(x)  //继承和构造函数参数. (wishlist: automatically pass-up params by default)
  13. object O extends D { ... }  //object定义单例
  14. trait T { ... } //traits.
  15. class C extends T { ... } //实现接口. no constructor params. mixin-able.
  16. class C extends D with T { ... }
  17. trait T1; trait T2 //多个traits
  18. class C extends T1 with T2
  19. class C extends D with T1 with T2
  20. class C extends D { override def f = ...} //必须声明override
  21. new java.io.File("f")  //产生类对象
  22. List(1,2,3)  
  23. classOf[String] //类字面值
  24. x.isInstanceOf[String] //运行时检查
  25. x.asInstanceOf[String] //运行时cast
  26. x: String //编译时指明
  27. final class A{
  28.   final val x = 1
  29.   var y = 2
  30. }
  31. sealed class B
复制代码


final和sealed
      对于内部类, inst1.InnerClass1 和inst2.InnerClass1是不同的类型,这和Java不一样。 如果想使用相同的类型,使用Class#InnerClass1
$ 泛型


  1. def mapmake[T](g:T=>T)(seq: List[T]) = seq.map(g)
复制代码


>> 方法带类型参数

  1. class Stack[T] {
  2. var elems: List[T] = Nil
  3. def push(x: T) { elems = x :: elems }
  4. def top: T = elems.head
  5. def pop() { elems = elems.tail }
  6. }
复制代码


>> 类带类型参数

  1. <p>class A
  2. class B extends A
  3. def test[T <: A](t: T) = {}
  4. test(new A)
  5. test(new B) //error
  6. Upper Type Bounds
  7. class A
  8. class B extends A
  9. class C extends B
  10. def test[T <: A](t: T) = {}
  11. test[A](new A)
  12. test[C](new C) //error</p>
复制代码
>>Lower Type Bounds
  1. class Test[+T](x: T)
复制代码
>> covariant 针对类
  1. class A
  2. class B extends A
  3. class C extends B
  4. class Test[T](x: T)
  5. val c = new Test(new C)
  6. val t:Test[B] = c //Note: C <: B, but class Test is invariant in type T. You may wish to define T as +T instead. (SLS 4.5)
  7. val a = new Test(new A)
  8. val t:Test[B] = a //Note: A >: B, but class Test is invariant in type. You may wish to define T as -T instead. (SLS 4.5)
复制代码

>>invariant

  1. class Test[-T](x: T)
复制代码


>>contravariant 针对类
总结:
1) 协变
[+T], covariant (or “flexible”) in its type parameter T,类似Java中的(? extends T), 即可以用T和T的子类来替换T,里氏替换原则。
2) 不变
不支持T的子类或者父类,只知支持T本身。
3) 逆变
[-T], contravariant, 类似(? supers T) 只能用T的父类来替换T。是逆里氏替换原则。
4) 上界
只允许T的超类U来替换T。 [U >: T]
5) 下界
只允许T的子类U来替代T。 [U <: T]
注解


  1. @interface SourceURL {
  2. public String value();
  3. public String mail() default "";
  4. }
复制代码


使用

  1. @interface Source {
  2. public String URL();
  3. public String mail();
  4. }
  5. @Source(URL = "http://coders.com/",
  6. mail = "support@coders.com")
  7. class MyScalaClass ...
复制代码


简写(对于属性名为value的特殊属性)


  1. @interface SourceURL {
  2.    public String value();
  3.    public String mail() default "";
  4.    }
  5.    @SourceURL("http://coders.com/")
  6. class MyScalaClass ..
  7. @SourceURL("http://coders.com/",
  8. mail = "support@coders.com")
  9. class MyScalaClass .
复制代码


Implicit
implicit parameters 隐式参数
如果参数定义为implicit,那么在调用的如果没设置, 那么参数会自动提供。
隐式参数与缺省参数是完全不一样的。缺省参数是函数定义方设定了一个缺省值,在调用者没有指明时将使用该缺省值。 隐式参数则不同,最终是会由调用方指定参数值,只是不一定在调用的语句里指定而已。编译器在发现缺少隐式参数时,会在程序范围内寻找符合类型的隐式值,如果找不到则编译会失败。

  1. abstract class Logger {def log(s: String)}
  2. class FileLogger extends Logger {
  3.   def log(s: String) {println("Log in file: " + s)}
  4. }
  5. class StdoutLogger extends Logger {
  6.   def log(s: String) {println("Stdout: " + s)}
  7. }
  8. def Add(a: Int, b: Int)(implicit logger: Logger) {
  9.   val sum = a + b
  10.   logger.log("%d + %d = %d".format(a, b, sum ))
  11. }
  12. implicit val log = new FileLogger
  13. Add(1,2)
  14. Add(2,3)(new StdoutLogger) //you may do it explicitly
复制代码


如果上述代码没有implicit val log = new FileLogger这一句,在代码范围内也没有其他的Logger类型的implicit值,编译器会报错.
反之,如果能找到Logger类型的隐式值,编译器会将该隐式值作为参数传递过去。
implicit class 隐式类
A new language construct is proposed to simplify the creation of classes which provide extension methods to another type.
  1. implicit class RichInt(n: Int) extends Ordered[Int] {
  2. def min(m: Int): Int = if (n <= m) n else m
  3. ...
  4. }
复制代码


被转换为
  1. class RichInt(n: Int) extends Ordered[Int] {
  2. def min(m: Int): Int = if (n <= m) n else m
  3. ...
  4. }
  5. implicit final def RichInt(n: Int): RichInt = new RichInt(n)
复制代码


>> implicit method 隐式转换
有时候,你并不需要指定一个类型是等/子/超于另一个类,你可以通过转换这个类来伪装这种关联关系。一个视界指定一个类型可以被“看作是”另一个类型。这对对象的只读操作是很有用的。
隐函数允许类型自动转换。更确切地说,在隐式函数可以帮助满足类型推断时,它们允许按需的函数应用。例如:

  1. implicit def strToInt(x: String) = x.toInt
  2. val y: Int = "123"
复制代码


>> view
view,就像类型边界,要求对给定的类型存在这样一个函数。您可以使用<%指定类型限制,例如:

  1. class Container[A <% Int] { def addIt(x: A) = 123 + x }
复制代码


这是说 A 必须“可被视”为 Int 。
方法可以通过隐含参数执行更复杂的类型限制。例如,List支持对数字内容执行sum,但对其他内容却不行。可是Scala的数字类型并不都共享一个超类,所以我们不能使用T <: Number。相反,要使之能工作,Scala的math库对适当的类型T 定义了一个隐含的Numeric[T]。 然后在List定义中使用它:


  1. sum[B >: A](implicit num: Numeric[B]): B
复制代码


如果你调用List(1,2).sum(),你并不需要传入一个 num 参数;它是隐式设置的。但如果你调用List("whoop").sum(),它会抱怨无法设置num。
在没有设定陌生的对象为Numeric的时候,方法可能会要求某种特定类型的“证据”。这时可以使用以下类型-关系运算符:
| | |
|---|---|
|A =:= B | A 必须和 B相等|
|A <:< B | A 必须是 B的子类|
|A <%< B | A 必须可以被看做是 B|


  1. class Container[A](value: A) { def addIt(implicit evidence: A =:= Int) = 123 + value }
复制代码


$ 空对象Nil,Null,null,Unit,Nothing,None

1) Nothing 是trait,定义为:final trait Nothing extends Any。Nothing处于Scala类型体系的最底层,是所有类型的子类型,Nothing没有实例。
2) Null 是trait,定义为:final trait Null extends AnyRef 。Null是所有引用类型的子类型,唯一的一个实例是null。
3) null是Null的实例,类似Java中的null
4) Nil 是case object,定义为case object Nil extends List[Nothing], 代表一个空list,长度为0。由于Scala中的List是协变的,因此无论T是何种类型,Nil都是List[T]的实例。
5) None 是case object,定义为:case object None extends Option[Nothing],代表不存在的值。Option有两个实例。None和Some
6) Unit 是class,定义为:abstract final class Unit extends AnyVal。Unit跟Java中的void相当,当一个方法不返回任何值的时候,那么方法的类型是Unit。Unit唯一的一个实例是().


来自群组: about云小组群
欢迎加入about云群425860289432264021 ,云计算爱好者群,亦可关注about云腾讯认证空间||关注本站微信

已有(10)人评论

跳转到指定楼层
落魂草 发表于 2015-3-28 19:40:27
回复

使用道具 举报

YLV 发表于 2015-3-31 10:04:28
总结的挺好
回复

使用道具 举报

cwcw2828 发表于 2015-4-13 10:02:31
回复

使用道具 举报

Elaine_VT2OO 发表于 2015-7-14 11:27:31
mark一下,又没有电子版书籍呢?
回复

使用道具 举报

pink_in_Paris 发表于 2016-4-7 15:06:42
mark,感谢分享!
回复

使用道具 举报

ningjianbang 发表于 2016-4-29 17:15:30
受教了!感谢分享!
回复

使用道具 举报

liwei 发表于 2016-8-2 10:43:20
感谢分享,不过说实话,没看懂,我还得找更基础的教程看看
回复

使用道具 举报

12下一页
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条