• Scala学习笔记(二)表达式和函数


    笔记的整理主要针对Scala对比Java的新特性;

     

    1、if表达式

    if表达式是有结果返回的。

    val a= if (5>2) “你好” else 1

    a的值为if表达式返回值为 “你好”

     

    2、while表达式

    while表达式是没有返回值的(返回值为 Unit),在scala中避免使用,通常都需要与var结合使用

     

    3、for表达式

    枚举集合遍历

    val a = Array(1,2,3,4,5,6)

    for (i <- a) println(i)

    以上for表达式遍历的语法成为发生器,不仅仅只是适合Array也适合其它集合类;

    for表达式中 to 与 until的区别:to包含上限,until不包含上限;

    遍历过滤

    for (i <- a if i>3) println(i)

    if i>3称为发生器i <- a 的守卫,主要用于对发生器产生的数据进行过滤;

    嵌套枚举

    for (i <- 0 to 5 if i>1 ;j <- 5 to 10 if j<9 ) println("i:"+i+",j:"+j)

    这里有两个发生器,每个发生器都带有一个守卫。

    执行的顺序为:先对将 i 赋值为一个合法的值(即满足区间在0~5之间且i大于1),然后依次完成对 j 合法值(即满足区间在5~10之间且 j小于9)的所有遍历,然后对 i 进行下一个合法值的遍历赋值,再重复对 j合法值的所有遍历,后面的过程以此类推;

    产生新集合结果

    val a = for (i <- 0 to 10 if i>5) yield i

    image

    for-yield语法:for (表达式) yield{循环体}

     

    4、本地函数

    特点:在方法中定义的方法,且本地方法仅在包含它代码块中可见(类似局部变量);

     

    5、头等函数

    把函数当值传递(如同变量),函数字变量被编译进类,并在运行期实例化为函数值。因此函数自变量与值的区别在于函数自变量存在于源码,而函数值做为对象存在于运行期(类似类与对象之间的关系);

    函数自变量的构成包含括号、参数列别、右箭头和函数体。如:(x:Int) => x+1 ; 右箭头左边为括号很参数,右边为函数体

    image 

    当编译器能推断出参数类型时,参数类型可以省略:

    var v = Array(1,2,3,4,5)

    v.foreach(x => println(x+1))

     

    6、占位符

    把下画线当做一个或更多参数的占位符,只要每个参数在函数字面量内仅出现一次。

    例如:

    scala> v.filter(_ > 0)
    res0: Array[Int] = Array(1, 3, 7)

     

    7、部分应用函数

    用单个下划线替换整个参数列表;

    例如:

    scala> def add (a:Int,b:Int) = a+b
    add: (a: Int, b: Int)Int

    scala> val sum = add _
    sum: (Int, Int) => Int = <function2>

    scala> sum(1,2)
    res1: Int = 3

    sum变量指向一个函数值对象,该函数值依照部分应用函数表达式add _,自动产生的类的一个实例,编译器产生的类有一个apply方法带两个参数,参数的个数有add _表达式缺少的参数数量确定;

    另一种表现形式(转换函数值):

    scala> def add(a:Int,b:Int) = a+b
    add: (a: Int, b: Int)Int

    scala> val sum = add(2,_:Int)
    sum: Int => Int = <function1>

    scala> sum(2)
    res2: Int = 4

    注意:一个省略所有参数的偏程序表达式(如:add _),且在代码的某个地方正需要一个函数,可以去掉下划线使表达式更简洁。如:scala> v.foreach(println)

     

    8、可变参数

    允许客户向函数传入可变长度参数列表,若想要标注一个重复参数,可在参数的类型之后放一个星号。

    例1:

    scala> def echo (args:String*)=
         | for (arg <- args)println(arg)
    echo: (args: String*)Unit

    scala> echo()

    scala> echo("hello","world")
    hello
    world

    例2:

    scala> var arr = Array("hello","world","chenx")
    arr: Array[String] = Array(hello, world, chenx)

    scala> def echo (args:String*)=for(arg <- args) println(arg)
    echo: (args: String*)Unit

    scala> echo(arr:_*)

    重复参数的类型是声明参数类型的数组,当参数类型为一个合适类型的数组时,需要在数组参数后添加一个冒号和一个_*符号。

     

    9、尾递归

    方法的最后一个动作是调用自己的函数称为尾递归。Scala对尾递归的情况进行了优化,比基于循环的实现更优美很简明,因为无需付出任何运行期开销,且递归必须是直接的。

    注:-g:notailcalls 参数传递给scala shell 或者scalac编译器,可用来跟踪堆栈信息。

     

    10、柯里化

    对柯里化的理解可以为根据方法参数的个数,对方法进行拆解,如:def f(a:Int,b:Int)=a+b 转换为 def f(a:Int)(b:Int)=a+b

    例1:

    scala> def f(a:Int)(b:Int)=a+b
    f: (a: Int)(b: Int)Int

    scala> val t = f(1)_
    t: Int => Int = <function1>

    scala> t(2)
    res0: Int = 3

    例2:

    scala> def f(a:Int)=(b:Int)=>a+b
    f: (a: Int)Int => Int

    scala> val t=f(1)
    t: Int => Int = <function1>

    scala> t(2)
    res1: Int = 3

    对比两个例子有一定的不同,例1使用占位符号获取f的第二函数,由f(1)_返回,例2运用的是方法f返回一个函数值并进行的下一步调用;

     

    11、控制抽象

    在传入一个参数时,用花括号替代小括号的机制。当参数为函数字面量时让方法的调用更像控制抽象;

    例:

    scala> def f(msg:String)(op:String => Unit){
         | op(msg)}
    f: (msg: String)(op: String => Unit)Unit

    scala> f("123456"){println(_)}
    123456

    该例中是将def f(msg:String,op:String => Unit)柯里化为def f(msg:String)(op:String => Unit),使其在调用函数字面量时能使用花括号,最后的println(_)也可以替换为 t => println(t),其中t为参数可任意命名;

    12、传名参数应用

    作用:在匿名函数基础上为函数命名;

    例:

    scala> def f(op:() => Boolean){
         | if (op())
         | println("OK")
         | else
         | println("ERROR")
         | }
    f: (op: () => Boolean)Unit

    scala> f(() => 5>3)
    OK

    • def f(op:() => Boolean)可转换为def f(op: => Boolean)并在在调用时可简化为f(5>3)即可;
    • def f(op:() => Boolean)与def f(op:Boolean)的区别,op:() => Boolean表示一个函数字面量,而op:Boolean表示参数Boolean两者有本质上的区别;
  • 相关阅读:
    完美解决Python与anaconda之间的冲突问题
    ansible之roles
    ansible剧本之playbook操作
    git从远程仓库拉取内容或向远程仓库上传内容
    python操作excel
    nginx基于uwsgi部署Django
    第二篇:版本控制git之分支
    笔试题92-101
    Django总结
    笔试题70-91
  • 原文地址:https://www.cnblogs.com/jianyuan/p/4257785.html
Copyright © 2020-2023  润新知