Scala语言初入门

来源:互联网 发布:美元霸主地位知乎 编辑:程序博客网 时间:2024/05/17 04:51

scala介绍

  • Scala语言来自于Scalable(可伸缩的)既可以写一些小的脚本,又可以写一写复杂的服务器端的程序。
  • Scala是一门纯正的面向对象语言,具有OO特征。
  • Scala是一门函数式语言,可以用函数式思想来编写代码
  • Scala是构建于JVM之上的,与java可以无缝互操作。

函数式编程思想

函数式编程基本名词介绍

纯函数来编写程序。

  • 纯函数(Pure Function),或函数的纯粹性(Purity)没有副作用(side Effect)
  • 副作用是状态的变化
    • 例子
    • 修改全局变量
    • 抛出异常
    • IO读写
    • 调用有副作用的函数
var x = 1def XplusY_V1(y:Int) = x + ydef XplusY_V2(y:Int) = {x += y;x}

上面第一个函数是输入一个int类型的y,第二个函数是输入一个int类型的y返回值是x。
第二个函数相对于第一个函数对变量x产生了副作用。改变了x的值。
* 引用透明(Referential Transparency)对于相同的输入,总能得到相同的输出。
如果f(x)的参数x和函数体都是引用透明的,那么函数f是纯函数。
违反引用透明

  • 不变性(Immutability)为了获得引用透明性,任何值都不能发生变化。
  • 函数是一等公民(First-class Function)一切都是计算,函数式编程中只有表达式,变量、函数都是表达式。
    函数也可以作为参数或者返回值。

  • 表达式求值策略:严格求值和非严格求职。
    Call By Value属于严格求值
    Call By Name属于非严格求职

  • 惰性求值(Lazy Evaluation)当定义这个变量时不会立即求值,只有在使用到这个变量时才会求值。
  • 递归函数(Recursive Function)
    在函数式编程中没有循环语句,所有的循环都要用递归来实现。
    递归有个性能问题。容易堆栈溢出。

* 尾递归(Tail Recursion)

函数式编程的优点

  • 生产效率高
    同样的功能,Lisp(世界上第一个函数式编程语言)代码长度可能是C代码长度的七到十分之一。
  • 易于推理
  • 并行编程
    因为是纯函数,所以不会引起线程紊乱。
  • 多核计算、云计算

搭建scala环境

安装JDK

下载JDK最新版本,将环境变量添加到配置文件中

安装Scala的运行环境和包

从http://www.scala-lang.org/download上下载了Scala的最新版本,将环境变量添加到配置文件中就可以用了。

REPL(Read Evaluate Print Loop)就是scala命令行的运行环境。

在linux命令行输入scala就可以直接进入到scala REPL中。

devil@devilshome:~$ scalaWelcome to Scala 2.12.0-M4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_60).Type in expressions for evaluation. Or try :help.scala> println("Hello World")Hello Worldscala> 

println()函数在所有Scala代码中都可用。

scala> val x =1x: Int = 1scala> var x = 1x: Int = 1scala> 

var 和 val 的区别稍后解释。

使用eclipse开发scala

在http://scala-ide.org/download/sdk.html下载专为scala的eclipse
- new一个Scala Project
- new 一个Scala Worksheet
worksheet是可以在IDE中直接进行代码的运行和结果的获得,是交互式的。
默认直接生成一个Object在eclipse中开发Scala

object worksheet {  println("Welcome to the Scala worksheet")       //> Welcome to the Scala worksheet  val x = 1                                       //> x  : Int = 1  println(x)                                      //> 1}

输入代码以后保存,会直接把输出的结果打印在右边。
新建一个package demo01
在package中新建一个scala app

package demo01object Greeting extends App {println("Hello,"+args(0)+"!")}

运行时设置main class和参数,main class的格式为包名.类名。
设置main class
设置参数
在控制台查看打印输出的结果

Hello,Devil!

使用命令行编译scala

在文件夹中新建一个.scala文件,如Greeting.scala
在命令行中键入

devil@devilshome:~/example$ scalac Greeting.scala

编译完成后,原文夹下多了一个Greeting.class文件,这个就是编译后的字节码文件。
再对这个字节码文件进行使用。

devil@devilshome:~/example$ scala Greeting JackHello,Jack!devil@devilshome:~/example$ scala Greeting DevilHello,Devil!

变量和表达式

变量

  • var 自动生成读写接口,代表的是一个可变的有类型的存储单元。可以在定义变量时为它指定数据,而且可以在任何时间重新赋值。
  • val 只生成了只读接口是一个不可变得、有类型的存储单元。可以在定义值时为它指定数据,不过不允许重新赋值,代表是一种函数式的思维。val蕴含了final的语义。
  • lazy val 定义惰性求值的常量。
    可以不显示指定变量的类型,因为Scala会自动进行类型推导。
scala> val x=10x: Int = 10scala> val y :Int =20y: Int = 20scala> x+xres0: Int = 20scala> res0res1: Int = 20scala> res0*res1res2: Int = 400scala> z=200<console>:16: error: reassignment to val       z=200        ^//val的值不能被修改scala> 
scala> val d = 20d: Int = 20scala> val e = 30e: Int = 30scala> lazy val f = d * ef: Int = <lazy>scala> f * 10res3: Int = 6000scala> fres4: Int = 600scala> 

精度问题

scala>  val b :Byte = 10b: Byte = 10scala> val x :Long = 10x: Long = 10scala> val y :Long = by: Long = 10scala> val z : Byte = x<console>:12: error: type mismatch; found   : Long required: Byte       val z : Byte = x                      ^scala> 
  • 字符类型
scala> val q = 'X'q: Char = X
  • Unit类型
    Scala中的Unit类型类似于java中的void。主要的不同是在Scala中可以有一个Unit类型值,也就是(),然而java中是没有void类型的值的。除了这一点,Unit和void是等效的。一般来说每一个返回void的java方法对应一个返回Unit的Scala方法。
scala> val u : Unit=()u: Unit = ()scala> val p = ()p: Unit = ()
  • Nothing
    对于一个函数而言,如果返回值是nothing,则表名该函数发生了异常。
scala> def foo() = throw new Exception("error occurred")foo: ()Nothing
  • String
    构建于java的String之上。
    新增了字符串插值(interpolation)的特性
scala> val name = "devil"name: String = devilscala> s"my name if ${name}"res5: String = my name if devil
  • Block
    在scala中,代码块用于组织多个表达式,block也是一个表达式,其最终的求得的值是最后一个表达式的值。

函数

object func_wxamples {  def hello(name: String): String = {    s"hello,${name}"  }                                               //> hello: (name: String)String  hello("devil")                                  //> res0: String = hello,devil  def hello2(name: String) = {    s"hello,${name}"  }                                               //> hello2: (name: String)String    hello2("devil")                           //> res1: String = hello,devil    def add (x:Int,y:Int) = x+y               //> add: (x: Int, y: Int)Int    add(5,3)                                  //> res2: Int = 8}

if表达式

在scala中,if是表达式,而不是语句。

object fun_if_example {  if (true) 1 else 2                              //> res0: Int = 1  if (false) 3 else 4                             //> res1: Int = 4  val a = 1                                       //> a  : Int = 1  if (a == 1) a                                   //> res2: AnyVal = 1  if (a != 1) "不是1"                               //> res3: Any = ()  if (a != 1) "不是1" else a                        //> res4: Any = 1}

for循环

object fun_for_examples {  val l = List("elisa", "sin", "satoshi")         //> l  : List[String] = List(elisa, sin, satoshi)  for (    s <- l //用s循环遍历l中的元素  ) println(s)                                    //> elisa                                                  //| sin                                                  //| satoshi  for (    s <- l if (s.length > 3)  ) println(s)                                    //> elisa                                                  //| satoshi  val result_for = for {    s <- l    s1 = s.toUpperCase()    if (s1 != "")  } yield (s1)                                    //> result_for  : List[String] = List(ELISA, SIN, SATOSHI)}

yield (s1)的意思是将s放入一个新的collection中。

try表达式

try{}catch{}finally{}//无论有没有发生异常,我们都会执行finally这个代码块

match表达式

exp match{    case p1 => val1    case p2 => val2    …    case _ => valn}
object func_match_example {    val code = 3                              //> code  : Int = 3    val result_match = code match{        case 1 => "one"        case 2 => "two"        case _ => "three"    }                                         //> result_match  : String = three}

求值策略

scala里有两种求值策略(Evaluation Strategy)
- Call By Value 对函数实参求值,且仅求值一次
- Call By Name 对函数实参每次在函数体内被用到时都会求值。

scala通常使用 Call By Value
如果函数性参类型以 => 开头,那么会使用Call By Name

def foo(x:Int) = x //Call By Valuedef foo(x:=>Int) = x //Call By Name
scala> def bar(x:Int,y: => Int)=1bar: (x: Int, y: => Int)Intscala> def loop(): Int = looploop: ()Intscala> bar(1,loop)res6: Int = 1scala> bar(loop,1)

第二个bar(loop,1)在进行死循环,因为x是Call By Value的需要对所有表达式求值才能进行下一步运算。

高阶函数

scala中函数是第一等公民
Scala语言支持:
1. 把函数作为实参传递给另外一个函数
2. 把函数作为返回值
3. 把函数赋值给变量
4. 把函数存储在数据结构中
在scala中,函数就像普通变量一样,同样也具有函数类型。

  • 在scala中,函数类型的格式为 A=>B,表示一个接收类型A的参数,并返回类型B的函数。

高阶函数
用函数作为形参或返回值的函数,成为高阶函数


匿名函数
就是函数常量,也成为函数文字量。
在scala里,匿名函数的定一个是为(形参列表)=>{函数体}

柯里化

柯里化函数把具有多个参数的函数转换为一条函数链,每个节点上是单一参数。

eg:下面两个函数的定义是等价的

def add(x: Int,y: Int) = x+y
def add(x: Int)(y: Int) = x+y

递归函数

递归函数在函数式变成中是实现循环的一种技术。

def factorial(n: Int): Int =    if (n<=0) 1    else n* factorial(n-1)

尾递归
尾递归函数中所有递归形式的调用都出现在函数的末尾。
当编译器检测到一个函数调用是尾递归的时候,它就覆盖当前的活动记录而不是在栈中去创建一个新的。
避免堆栈溢出

    @annotation.tailrec //告诉scala编译器,对这个递归进行尾递归优化    def factorial(n: Int,m: Int): Int =        if (n<=0) m        else factorial(n-1,m*n)    factorial(5,1)

在上面这个案例增加了一个m,m其实是保留了n*n-1*n-2……这样一个累乘器。
m永远拿到都是过去几次累乘的结果。

0 0
原创粉丝点击