前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Scala的基础概念

Scala的基础概念

作者头像
ZONGLYN
发布2019-08-08 11:49:12
7110
发布2019-08-08 11:49:12
举报
文章被收录于专栏:程序萌部落程序萌部落

Scala语言的特性

Scalable语言 Scala是一门可伸缩的scalable语言,既可以写复杂的服务器端程序,也可以写简单的脚本 纯正的面向对象 所有的概念最终都会被时限为纯正的对象 函数式编程的特性 函数式程序思想!!! 无缝的Java互操作 构建于Jvm之上,Java的包可以在Scala中使用,huo1Scala写好的程序给Java调用 编程思路灵活 既可以面向对象的思想,也可以函数式编程的思想

Scala之父:Martin Odersky

导读: 函数式变成的概念和思想 Scala的开发环境搭建 Scala语言的基础 Scala中的类型和求值策略 Scala中函数的概念 Immutable Collections如何用函数式思想实现数据结构和其上的一些操作

函数式编程思想

只用纯函数编程

定义:函数式编程是一种编程范式,构建计算机程序和结构的方法和风格,把计算当做数学函数求值的过程,并且避免了改变状态和可变的数据

纯函数特点 Pure Function

纯函数,没有副作用的函数

没有副作用:状态的变化

例如:调用 def Add(y:Int) = x + y 其结果为xy之和,并且调用之后没有引起x值的变换,没有副作用 所以,Add函数没有副作用

引用透明性

对于上述Add函数,对于同一输入y,返回结果均相同 所以,Add具有引用透明性

如何确保引用透明

不变性Immutablity:任何的状态和值都是不变的,才能获得引用透明 函数与变量,对象类是同一级的,即函数中可以定义函数,有变量的地方都可以使用函数,都是等同的

高阶函数

函数作为一个函数的输入或另一个函数的输出

闭包 closure
表达式求值

函数式编程中,一切都是表达式,表达式求值策略:

严格求值:call by value 非严格求值:call by name

惰性求值

定义表达式时不会立即求值,只在第一次调用时才求值

递归函数

函数式编程中没有循环语句,全部的循环用递归实现 调优递归:尾递归

函数式编程的优点

Lisp是第一种函数式编程语言

  1. 编程代码量少
  2. 当构造完含数之后,对于相同输入,输出相同,便于调试
  3. 非常适用于并行编程,没有副作用,具备引用透明性,在n个节点运算结果是相同的
  4. 传统语言多核编程非常复杂

Scala环境的搭建

安装Jdk6以上,并安装Scala包

Scala基础语法

变量修饰符

  1. val 定义 immutable variable 常量
  2. var 定义 mutable variable 变量
  3. lazy val 惰性求值的常量

定义时不用显示的说明类型,scala会自己进行变量推导

前两种定义,在定义时表达式就会立即求值 lazy val 在REPL中,scala会给没有变量名的变量自动取值resN,可以直接引用已有的resN 注意: scala中不允许常量定义后被直接改变,而变量var可以 val x = 10 x = 20 //会报错reassignment to val val x = 20 //正确的重新赋值,需要使用val重新定义 对于lazy val,注意没有lazy var,一般是定义惰性求值的表达式 val l = 常量或变量组成的表达式

Scala的类体系

Any 所有类的父类 AnyVal 值类型 NumericTypes 数值类型 Byte,Shot,Int,Long,Float,Double Boolean 布尔类型 Char 字符类型 Unit 空类型,相当于Java的void AnyRef 所有引用类型的父类 All java. ref types 所有Java的引用类都是其子类 All scala. ref types 所有自定义的scala的类都是其子类 Null 所有引用类型的最后一个子类 Nothing 所有类型的最后一个子类(既是AnyVal又是AnyRef的子类)

  1. NumericTypes 对于数值类型:低精度可以赋值给高精度,反之不行,数据会缺失:报类型不匹配错误
  2. Unit 往往作为函数的返回值出现,表明函数有副作用
  3. Null 表示一个引用类型的值为空。通常不使用
  4. Nothing 对于函数而言,如果返回值为nothing,那么则表示函数异常 scala> def foo() = throw new Exception(“1111”) foo: ()Nothing
  5. String 新特性 - 字符串插值(interpolation) scala> val name=”Jack” name: String = Jack scala> s”my name is $name” //使用字符串插值 res11: String = my name is Jack

代码块Block

代码块用于组织多个表达式:{exp1;exp2} 多个表达式在一行2时需要分号分割,代码块本事也是一个表达式 最后的求值,是最后一个表达式

函数

定义函数的方式: def functionName(param:paramType):returnType = { //body expressions } 示例:

代码语言:javascript
复制
  object worksheetA {
      // 完整形式
def Hello(name:String):String = {
		s"Hello,$name"
}                                 //> Hello: (name: String)String
Hello("Jack")                     //> res0: String = Hello,Jack
// 省略返回值,自动推断类型
def Hello2(name:String) = {
		s"Hello,$name"
}                                 //> Hello2: (name: String)String
Hello2("Tom")                     //> res1: String = Hello,Tom
// 单语句的函数体
def add(x:Int,y:Int) = {
		x + y
}                                 //> add: (x: Int, y: Int)Int
// 可以省略大扩号
//def add(x:Int,y:Int) = x + y
add(1,2)                          //> res2: Int = 3
  }

scala中的if

if是表达式,而不是语句 if(逻辑表达式) valA else valB val a = 1 //> a : Int = 1 if(a!=1) “not none” //> res3: Any = ()返回空 if(a!=1) “not none” else a //> res4: Any = 1

scala中的for comprehension

用于实现循环的一种推导式,本身是由map() reduce()组合实现的 是scala语法糖(thin text sugar)的一种

代码语言:javascript
复制
for{
    x <- xs
    y = x + 1
    if( y > 0)
}yield y

示例:

代码语言:javascript
复制
  object worksheetA {
//初始化一个List
val list = List("alice","bob","cathy")
for (
		//遍历list每一个元素给s,generator
		s <- list
)println(s)
for {
		s <- list
		//串长度大于三才被打印
		if( s.length > 3)
}println(s)
val res_for = for{
		s <- list
		//变量绑定,variable binding
		s1 = s.toUpperCase()
	if ( s1 != "")
//yeild导出的意思,如果每次s1不空,则生成新的collection
}yield (s1)
  }

scala中的try

try也是一个表达式,返回一个值

代码语言:javascript
复制
try{
    Integer.praseInt("dog")
}catch{
    case _ => 0  //下划线是通配符,统配所有异常
}finally{
    print("总是会打印");
}

scala中的macth

类似switch,但也是一个表达式,返回相应的值,主要用在 pattern match

代码语言:javascript
复制
var expression = 1                  //> expression  : Int = 1
expression match{
       case 1 => "dog"
       case 2 => "cat"
       //类似switch的default
       case _ => "others"
   }                                   //> res5: String = dog

Scala的求值策略

scala中所有运算都是基于表达式的,求值会有不同策略

  1. call by value 对函数实参求值,仅求一次,求得的值直接替换函数中的形式参数
  2. call by value 不会对函数实参进行表达式求值,直接把表达式传入函数体内,替换表达式的形参,然后在函数内每次使用到此形参时会被求值

scala通常使用call by value

def foo(x: Int) = x //call by Value def foo(x: => Int) = x //call by Name

下面是两种求值策略在不同情况下的运行机制:

代码语言:javascript
复制
def add(x: Int,y: Int) = x * x      def add(x: =>Int,y: =>Int) = x * x
add(3+4,7)                          add(3+4,7) 
=>add(7,7)                          =>(3+4)*(3+4)
=>7*7                               =>7*(3+4)
=>49                                =>7*7
                                    =>49
                                
add(7,3+4)                          add(7,3+4)
=>add(7,7)                          =>7*7
=>7*7                               =>49
=>49

注意上述运行机制的区别

代码语言:javascript
复制
scala> def bar(x:Int, y: => Int) : Int = 1
bar: (x: Int, y: => Int)Int
scala> def loop():Int = loop
loop: ()Int
scala> bar(1,loop) 
//loop函数位于的参数的定义方式是y: => Int,即call by name,不进行求值,会带到函数体内并且使用时
才求值,此处,loop没有机会执行。
res0: Int = 1
scala> bar(loop,1)
//loop函数位于的参数的定义方式是y: Int,即call by value,会直接将表达式求值并代替形参,此处loop
首先被执行求值,故而陷入死循环。
输出:死循环

进行函数设计和调用时,两种差异要搞清楚

Scala中的函数

  1. 支持把函数作为实参传递给另外一个函数
  2. 支持把函数作为返回值
  3. 支持把函数赋值给变量
  4. 支持把函数存储在数据结构里

即,在scala中,函数跟普通变量一样使用,且具有函数的相关类型

函数的类型

在scala中,函数类型的格式为 A => B,表示一个:接受参数类型为A的、并返回类型B的函数 eg: Int => String 是把整型映射为字符串的函数类型

高阶函数

  1. 接受的参数为函数
代码语言:javascript
复制

def funcName( f: (Int, Int) => Int) = {
    f(4,4)
}

参数:f 类型:Int => Int 返回:Int类型

返回值为一个函数

代码语言:javascript
复制
def funcName() = ( name: String) => {"hello "+name} 

参数:name 类型:String => String 返回:String类型 注意上述叫做:匿名函数 - 函数常量 - 函数的文字量(相对于def funcName 叫函数变量)

  1. 兼具上述情况

匿名函数

匿名函数没有函数名 定义格式: (形参列表) => { 函数体 }

  • (x: Int) => { x * x }

(x: Int,y: Int) => { x + y }

var add = (x: Int,y: Int) => { x + y }

代码语言:javascript
复制
scala> (x: Int,y: Int) => { x + y }
res0: (Int, Int) => Int = $$Lambda$1016/2093139281@69feb4d9
scala> var add = (x: Int,y: Int) => { x + y }
add: (Int, Int) => Int = $$Lambda$1025/1152113439@62108cd3
scala> add(1,2)
res1: Int = 3
scala> def funcName() = ( name: String) => {"hello "+name}
funcName: ()String => String
scala> funcName()("Jack")
res4: String = hello Jack

柯里化

Scala中的重要的技术,具有多个参数的函数转化成一个函数列,每个函数只有单一参数

代码语言:javascript
复制
def add(x: Int,y: Int) = { x + y }  //普通函数定义
def add(x: Int)(y: Int) = { x + y } //柯里化函数定义,多个参数单一化,串接起来
def curriedAdd(a: Int)(b: Int) = a + b
curriedAdd(2)(2) //4
val add = curriedAdd(1)_    //Int => Int
add(2)  //3

解释:curriedAdd(1)_,下划线统配之后的全部参数列表,此处a=1固定,只有b是可变值,下划线通配变量b add(2),传入curriedAdd后a=1,b=2

利用柯里化技术,通过原有通用函数构造一些新的函数

Scala中的递归

scala里计算n的阶乘

代码语言:javascript
复制
def factorial(n: Int): Int = 
    if(n <= 0) 1
    else n * factorial(n - 1)

递归优化:变成尾递归,尾递归会复写当前栈,不会导致堆栈溢出 尾递归优化:用¥annotation.tailrec显示指明编译时进行尾递归优化

代码语言:javascript
复制
@annotation.tailrec
def factorial(n: Int,m: Int): Int = 
    if(n <= 0) m
    else factorial(n - 1, m * n)
factorial(5,1)

上述引入m,m保留当前运算之前的历史阶乘结果 如果退出,则就是递归的值,如果不退出,那么把当前结果传入下一次,这样不需要开辟栈保留计算结果,每次只需m变量记录结果 示例:求f(x)在(a,b)上的和

代码语言:javascript
复制
def sum(f: Int => Int)(a: Int)(b: Int): Int = {
		
		@annotation.tailrec
		def loop(n: Int, acc: Int): Int = {
		//函数中可定义其他函数
		//n:循环变量
		//acc:累积和
				if (n > b) {
						println(s"n=${n}, acc=${acc}")
						acc
						//if表达式返回acc的值
				} else {
						println(s"n=${n}, acc=${acc}")
						loop(n + 1, acc + f(n))
						//else表达式返回loop
				}
		}
		loop(a, 0)
}                               //> sum: (f: Int => Int)(a: Int)(b: Int)Int
//函数y=f(x)
sum(x => x)(1)(5)               //> n=1, acc=0
                                  //| n=2, acc=1
                                  //| n=3, acc=3
                                  //| n=4, acc=6
                                  //| n=5, acc=10
                                  //| n=6, acc=15
                                  //| res0: Int = 15
                                                
                                                
  sum(x => x * x)(1)(5)           //> n=1, acc=0
                                  //| n=2, acc=1
                                  //| n=3, acc=5
                                  //| n=4, acc=14
                                  //| n=5, acc=30
                                  //| n=6, acc=55
                                  //| res1: Int = 55
                                                
                                                
                                                
  sum(x => x * x * x)(1)(5)       //> n=1, acc=0
                                  //| n=2, acc=1
                                  //| n=3, acc=9
                                  //| n=4, acc=36
                                  //| n=5, acc=100
                                  //| n=6, acc=225
                                  //| res2: Int = 225
   
  //利用柯里化技术,通过原有通用函数构造一些新的函数,简化代码
                                                
  val sumSquare = sum(x => x * x)_              
  //> sumSquare  : Int => (Int => Int) = sumfunc$$$Lambda$13/2054798982@34ce8af7
	 
sumSquare(1)(5)                 //> n=1, acc=0
                                  //| n=2, acc=1
                                  //| n=3, acc=5
                                  //| n=4, acc=14
                                  //| n=5, acc=30
                                  //| n=6, acc=55
                                  //| res3: Int = 55
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-10-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Scala语言的特性
  • Scala之父:Martin Odersky
  • 函数式编程思想
    • 只用纯函数编程
      • 纯函数特点 Pure Function
        • 没有副作用:状态的变化
        • 引用透明性
        • 高阶函数
        • 闭包 closure
        • 表达式求值
        • 惰性求值
        • 递归函数
    • 函数式编程的优点
    • Scala环境的搭建
    • Scala基础语法
      • 变量修饰符
      • Scala的类体系
      • 代码块Block
      • 函数
      • scala中的if
      • scala中的for comprehension
      • scala中的try
      • scala中的macth
      • Scala的求值策略
        • scala通常使用call by value
        • Scala中的函数
          • 函数的类型
            • 高阶函数
              • 匿名函数
                • 柯里化
                • Scala中的递归
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档