zoukankan      html  css  js  c++  java
  • Scala学习-变量常量、运算符、流程控制和函数

    scala是马丁.奥德斯克设计的,专门为程序员设计,广泛应用于大数据的语言。它同时支持面向对象和面向函数编程,运行scala需基于JVM,使用它需要提前安装好JDK和scala SDK。scala的的代码一行可以顶多行java代码,开发效率高,并且兼容java类库,scala编译完也是.class文件。另外大数据框架kafka和spark是基于scala开发的,因此想做流处理需要学习scala。

    基本数据类型

    scala中没有基本类型的说法,绝大多数类型(类似java类型)都封装成了类,以下是它的简图。

    (1)Any是scala顶级父类。

    (2)AnyVal是所有数值类型的父类,注意有一个Unit,它只有一个实例()。

    (3)AnyRef是所有对象类型的父类,注意Null是它的子类,它的实例对象是null,可以赋值给任意对象类型。

    (3)Nothing可以是任何类型的子类,可以表示不正常的返回值类型,如异常。

    # RPEL交互方式
    scala> def test():Nothing={
         | throw new IllegalArgumentException()
         | }
    test: ()Nothing
    

    变量和常量

    变量声明的语法:'var 变量名:数据类型=数据值' 或者 'var 变量名=数据值',后者会进行自动类型转换。常量声明类似,使用val代表常量。

    使用变量或常量需要标识符的支撑,scala中也有一套标识符规则。

    标识符规则

    (1)使用数字、字母、下划线和$符号;

    scala> var name:String="clyang"
    name: String = clyang
    
    scala> var age:Int=28
    age: Int = 28
    

    (2)不能以数字开头;

    (3)如果有特殊字符,标识符全部都需要是特殊字符;

    scala> var +-*/ :Double=3.14
    +-*/: Double = 3.14
    

    (4)可以使用``来标记任何字符;

    # 可以用scala的关键字,任何字符均可
    scala> var `private`:String="test"
    private: String = test
    

    (5)见名知意;

    # year代表年,365天
    scala> val year:Int=365
    year: Int = 365
    
    # 如果是常量,声明后不可以修改
    scala> year=3650
    <console>:13: error: reassignment to val
           year=3650
               ^
    

    类型转换

    (1)自动类型推导

    # 自动识别类型
    scala> var name="clyang"
    name: String = clyang
    
    scala> var age=28
    age: Int = 28
    

    (2)手动指定向上类型,否则按自动类型推导出数据类型

    # 默认是Double类型,手动指定Any类型
    scala> var a:Any=3.14
    a: Any = 3.14
    

    (3)强制转换,从大往小转

    # 强制Double转Int
    scala> var d:Double=3.14
    d: Double = 3.14
    
    scala> var i:Int=d.toInt
    i: Int = 3
    

    (4)自定义类型转换,需自定义函数,可以显示调用和隐式调用。

    显示调用

    # 自定义类型转换函数
    scala> def string2Int(str:String):Int={
         | return Integer.parseInt(str)
         | }
    string2Int: (str: String)Int
    # 给一个字符串
    scala> var str="268"
    str: String = 268
    # 调用转换
    scala> var number=string2Int(str)
    number: Int = 268
    
    
    

    隐式调用

    # 需使用implicit关键字
    scala> implicit def string2Int(str:String):Int={
         | return Integer.parseInt(str)
         | }
    warning: there was one feature warning; re-run with -feature for details
    string2Int: (str: String)Int
    
    scala> str
    res1: String = 268
    
    scala> var number:Int=str
    number: Int = 268
    
    

    (5)向上造型创建的对象,可以使用asInstanceOf来向下转。

    # 定义Person类
    scala> class Person{}
    defined class Person
    
    # 创建Any类型的对象,向上造型
    scala> var p:Any=new Person()
    p: Any = Person@6a370f4
    
    # 向下转
    scala> var s:Person=p.asInstanceOf[Person]
    s: Person = Person@6a370f4
    
    

    运算符

    scala中运算符包括算术、赋值、关系、逻辑和位运算,注意没有三元运算,并且所有的运算符都封装成了方法。

    参考菜鸟教程:https://www.runoob.com/scala/scala-operators.html

    算术

    注意一下,scala中的运算符是封装成了方法,因此a+b,其实就是a.+(b)的简写,其他依次类推。

    scala> var a=500
    a: Int = 500
    
    scala> var b=20
    b: Int = 20
    
    # 加
    scala> a+b
    res2: Int = 520
    
    # 完整写法
    scala> a.+(b)
    res3: Int = 520
    
    # 以下三种方式等效,都可以加1
    scala> a=a+1
    a: Int = 501
    
    scala> a+=1
    
    scala> a
    res5: Int = 502
    
    scala> a.+=(1)
    
    scala> a
    res7: Int = 503
    
    

    如果有点,则计算点。

    //运算符运用,有点先算点
    println(3+5*7)//38
    println(3+(5)*7)//38
    println(7*3.+(5)) //56
    println(7*3+5) //26
    println(7*(3).+(5)) //56
    println(3.+(5).*(7))//56
    
    

    赋值

    scala> var a=520
    a: Int = 520
    
    scala> var b=1314
    b: Int = 1314
    
    # 赋值运算的返回值类型为Unit,对应实例对象为()
    scala> var z:Unit=a=b
    z: Unit = ()
    
    # a被赋值为1314
    scala> a
    res8: Int = 1314
    
    

    关系

    就是类似java中的大于小于等于之类的。

    scala> var r=1314>520
    r: Boolean = true
    scala> var r="婚姻"=="车子房子票子"
    r: Boolean = false
    
    

    逻辑

    逻辑与、逻辑或和逻辑非。

    scala> var r=true&&true
    r: Boolean = true
    
    scala> var r=true&&false
    r: Boolean = false
    
    

    位运算

    类似java中的位运算符,按位与、按位或、按位异或、取反、左移、右移、无符号右移。

    //判断一个数是否是2的幂
    println(8&7)//0
    //左移比直接相乘快
    println(4<<2)//16
    println(~4)//-5 取反减1
    
    

    流程控制

    scala中没有switch-case,有条件判断和循环。

    if条件判断

    类似java,scala中if-else是有返回值结果的,根据if-else的{}最后一行来确认。

    package day01.clyang.control
    
    import scala.io.StdIn
    
    /**
      * 流程控制
      */
    object IfDemo2 {
    
      def main(args: Array[String]): Unit = {
        //if-else是有返回值结果的,根据if-else的{}最后一行来确认
        var i=StdIn.readInt()
        var result:String=if(i%2!=0){
          println("~~~")
          "我是谁我在哪里"
          "奇数"//最后一行
        }else{
          "偶数"//最后一行
        }
        //打印result
        println(result)
      }
    
    }
    
    

    控制台输入奇数后,只返回最后一行'奇数'。

    99
    ~~~
    奇数
    
    

    scala中也支持if-else if。

    package day01.clyang.control
    
    import scala.io.StdIn
    
    /**
      * 多级if-else
      */
    object IfDemo3 {
      def main(args: Array[String]): Unit = {
        var score=StdIn.readInt()
        var result:String=if(score>90) "优秀"
        else if(score>80) "良好"
        else if(score>=70) "一般"
        else "及格"
        //打印结果
        println(result)
      }
    }
    
    

    控制台输入测试,ok。

    98
    优秀
    
    

    循环

    可以使用while循环,和for循环。

    (1)while循环

    # while循环,返回值类型为Unit
    scala> var count=0
    count: Int = 0
    
    scala> var result=while(count<3){
         | println("while")
         | count=count+1
         | }
    while
    while
    while
    result: Unit = ()
    
    

    (2)do-while循环,这个用的少

    # do-while返回值类型也是Unit
    scala> var count=0
    count: Int = 0
    
    # scala中,也类似python中,字符串可以和数字相乘
    scala> var result=do{
         | println("*"*5)
         | count=count+1
         | }while(count<3)
    *****
    *****
    *****
    result: Unit = ()
    
    

    (3)for循环

    注意to和until的使用,两者均是函数。

    # 准备一个数组
    scala> var arr:Array[Int]=Array[Int](1,2,3,4,5)
    arr: Array[Int] = Array(1, 2, 3, 4, 5)
    # to为后包括
    scala> var result=for(i <- 0 to arr.length-1){
         | println(arr(i))
         | }
    1
    2
    3
    4
    5
    result: Unit = ()
    # until为后不包括
    scala> var result=for(i <- 0 until arr.length){
         | println(arr(i))
         | }
    1
    2
    3
    4
    5
    result: Unit = ()
    
    

    to和until都是函数,如果要指定步长,就不能省略.和( )。

    # 指定步长,打印0到10范围的偶数
    scala> for(i <- 0.to(10,2)){
         | println(i)
         | }
    0
    2
    4
    6
    8
    10
    # 倒着来
    scala> for(i <- 10.to(0,-2)){
         | println(i)
         | }
    10
    8
    6
    4
    2
    0
    # reverse倒着来
    scala> for(i <- 0 to 3 reverse){
         | println(i)
         | }
    warning: there was one feature warning; re-run with -feature for details
    3
    2
    1
    0
    
    

    for循环最后一行的结果,可以通过yield关键字把它放到一个集合,集合类型是Vector。

    scala> import scala.io.StdIn
    import scala.io.StdIn
    # 输入5
    scala> var n=StdIn.readInt()
    n: Int = 5
    # 返回集合类型为Vector
    scala> var result=for(i <- 0 to n) yield i*i
    result: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 4, 9, 16, 25)
    
    
    

    for循环中,如果嵌套了if判断,就构成了守卫循环。

    # 打印100以内5的倍数,但是不是7的倍数
    scala> for(i <- 0.to(100,5)){
         | if(i%7!=0){
         | println(i)
         | }
         | }
    5
    10
    15
    20
    25
    30
    40
    45
    50
    55
    60
    65
    75
    80
    85
    90
    95
    100
    # 可以使用守卫循环
    scala> for(i <- 0.to(100,5) if(i%7!=0)){
         | println(i)
         | }
    5
    10
    15
    20
    25
    30
    40
    45
    50
    55
    60
    65
    75
    80
    85
    90
    95
    100
    
    

    for循环嵌套,scala中还有大括号写法。

    # 普通写法
    scala> for(i <- 1 to 9){
         |   for(j <- 1 to i){
         |   print(i+"*"+j+"="+i*j+"	")
         |   }
         | println()
         | }
    1*1=1
    2*1=2	2*2=4
    3*1=3	3*2=6	3*3=9
    4*1=4	4*2=8	4*3=12	4*4=16
    5*1=5	5*2=10	5*3=15	5*4=20	5*5=25
    6*1=6	6*2=12	6*3=18	6*4=24	6*5=30	6*6=36
    7*1=7	7*2=14	7*3=21	7*4=28	7*5=35	7*6=42	7*7=49
    8*1=8	8*2=16	8*3=24	8*4=32	8*5=40	8*6=48	8*7=56	8*8=64
    9*1=9	9*2=18	9*3=27	9*4=36	9*5=45	9*6=54	9*7=63	9*8=72	9*9=81
    # 两个循环嵌套到一起,scala中不推荐使用分号
    scala> for(i <- 1 to 9; j <- 1 to i){
         | print(i+"*"+j+"="+i*j+"	")
         | if(i==j) println()
         | }
    1*1=1
    2*1=2	2*2=4
    3*1=3	3*2=6	3*3=9
    4*1=4	4*2=8	4*3=12	4*4=16
    5*1=5	5*2=10	5*3=15	5*4=20	5*5=25
    6*1=6	6*2=12	6*3=18	6*4=24	6*5=30	6*6=36
    7*1=7	7*2=14	7*3=21	7*4=28	7*5=35	7*6=42	7*7=49
    8*1=8	8*2=16	8*3=24	8*4=32	8*5=40	8*6=48	8*7=56	8*8=64
    9*1=9	9*2=18	9*3=27	9*4=36	9*5=45	9*6=54	9*7=63	9*8=72	9*9=81
    # 大括号写法
    scala> for{
         | i <- 1 to 9
         | j <- 1 to i
         | }
         | {
         | print(i+"*"+j+"="+i*j+"	")
         | if(i==j){
         |   println()
         |   }
         | }
    1*1=1
    2*1=2	2*2=4
    3*1=3	3*2=6	3*3=9
    4*1=4	4*2=8	4*3=12	4*4=16
    5*1=5	5*2=10	5*3=15	5*4=20	5*5=25
    6*1=6	6*2=12	6*3=18	6*4=24	6*5=30	6*6=36
    7*1=7	7*2=14	7*3=21	7*4=28	7*5=35	7*6=42	7*7=49
    8*1=8	8*2=16	8*3=24	8*4=32	8*5=40	8*6=48	8*7=56	8*8=64
    9*1=9	9*2=18	9*3=27	9*4=36	9*5=45	9*6=54	9*7=63	9*8=72	9*9=81
    
    

    Break

    scala中,没有break和continue关键字,如果要退出循环,可以使用Break类来跳出循环。

    (1)跳出循环,报异常,并且for循环后面语句不执行。

    for(i <- 0.to(50,5)){
          if(i==35) Breaks.break()
          println("我今年"+i+"岁,我依然很帅")
        }
    //测试是否执行后面语句
    println("finished~~")
    
    # console显示没有打印
    我今年0岁,我依然很帅
    我今年5岁,我依然很帅
    我今年10岁,我依然很帅
    我今年15岁,我依然很帅
    我今年20岁,我依然很帅
    我今年25岁,我依然很帅
    我今年30岁,我依然很帅
    Exception in thread "main" scala.util.control.BreakControl
    
    

    如果按以下这么写,即使跳出循环,依然执行for循环后面的语句。

    Breaks.breakable(
      for(i <- 0.to(50,5)){
        if(i==35) Breaks.break() 
        println("我今年"+i+"岁,我依然很帅")
      }
    )
    //测试是否执行后面语句
    println("finished~~")
    
    # console显示打印了后面的语句
    我今年0岁,我依然很帅
    我今年5岁,我依然很帅
    我今年10岁,我依然很帅
    我今年15岁,我依然很帅
    我今年20岁,我依然很帅
    我今年25岁,我依然很帅
    我今年30岁,我依然很帅
    finished~~
    
    # import scala.util.control.Breaks._后,这么写也行
    breakable(
      for(i <- 0.to(50,5)){
        if(i==35) break()
        println("我今年"+i+"岁,我依然很帅")
      }
    )
    
    println("finished~~")
    
    

    函数

    函数在scala中地位非常高,是"一等公民",它可以作为函数的参数,也可以作为函数的返回值,并且可以定义在任何地方,函数定义的基本语法如下。

      /*
       * 函数的格式
       * def 函数名(参数列表):返回值类型={
       *   函数体
       *   return 返回值
       *   }
       */
    
    

    入门使用

    常规写法。

    scala> def max(i:Int,j:Int):Int={
         | return if(i>j) i else j
         | }
    max: (i: Int, j: Int)Int
    # 调用
    scala> max(1,3)
    res0: Int = 3
    
    

    如果没有return,默认将函数体最后一行的结果返回。

    scala> def sum(i:Int,j:Int):Int={i+j}
    sum: (i: Int, j: Int)Int
    
    scala> sum(1,3)
    res1: Int = 4
    
    

    如果函数体只有一句,大括号可以省略,如果可以根据最后一行推导出返回值类型,方法返回值类型也可以省略。

    scala> def sum(i:Int,j:Int)=i+j
    sum: (i: Int, j: Int)Int
    
    scala> sum(1,3)
    res2: Int = 4
    
    

    如果没有指定方法的返回值类型,方法体不能用return,根据函数体最后一行来推导。

    scala> def sum(i:Int,j:Int)={return i+j}
    <console>:10: error: method sum has return statement; needs result type
           def sum(i:Int,j:Int)={return i+j}
                                 ^
    
    

    方法如果没有返回值类型,可以使用Unit作为返回值类型。

    scala> def printShape(row:Int,col:Int):Unit={
         | for(i <- 1 to row)
         |   println("*"*col)
         | }
    printShape: (row: Int, col: Int)Unit
    
    scala> printShape(3,3)
    ***
    ***
    ***
    
    

    如果没有写返回值类型,也没写等号,则默认返回值类型为Unit。

    scala> def printTest(){
         | println("this is return Unit")
         | }
    printTest: ()Unit
    # 如果函数没有参数,可以省略括号
    scala> printTest
    this is return Unit
    
    

    函数进阶

    scala可以直接调用java api。

    scala> def getRandom()=(Math.random()*11).toInt
    getRandom: ()Int
    # 调用时加括号
    scala> getRandom()
    res7: Int = 0
    # 没有参数,调用时括号可以省略
    scala> getRandom
    res8: Int = 10
    # 方法没有参数,方法括号也可以省略
    scala> def getRandom=(Math.random()*11).toInt
    getRandom: Int
    scala> getRandom
    res9: Int = 3
    
    

    scala中函数可以重载,类似java,根据方法签名来绑定执行的方法。

    //scala中函数可以重载
    def square(x:Int,y:Int)=x*y
    def square(r:Int)=3.14*r*r
    
    //根据参数不同,重载,好像一次只能调用一个,同时调用两个也只显示一个的结果
    
    

    函数定义时如果没有(),调用时就不能加()。

    scala> def test="this is test"
    test: String
    # 正常调用
    scala> test
    res15: String = this is test
    # 加括号调用就报错
    scala> test()
    <console>:12: error: not enough arguments for method apply: (index: Int)Char in class StringOps.
    Unspecified value parameter index.
           test()
               ^
    
    

    高阶函数

    将函数作为参数,或者函数的返回值也是函数,这样的函数叫做高阶函数,前面的闭包和柯理化就是高阶函数,返回值类型是函数。

    (1)闭包

    函数中嵌套函数,可以延长变量的生命周期,这是函数的闭包。

    # 定义函数,打印最小值,如果有必要可以获取两个较大值的和
    # 返回值为函数
    scala> def min(x:Int,y:Int,z:Int)={
         | var min=x
         | if(y<min) min=y
         | if(z<min) min=z
         | println("最小值为:"+min)
         |   def sum(){ # 内部定义函数,返回值类型为Unit
         |   println(x+y+z-min) 
         |   }
         | sum _ # 将sum一整个函数作为返回值,调用它才执行sum方法,不调用就不执行
         | }
    min: (x: Int, y: Int, z: Int)() => Unit
    # 打印最小值,返回值类型是一个函数,() => Unit就是min方法返回值类型
    scala> min(1,2,3)
    最小值为:1
    res17: () => Unit = <function0>
    # 调用sum方法
    scala> min(1,2,3)()
    最小值为:1
    5
    
    

    min函数执行完后,会移除出栈内存,如果将参数也移除,那接下来如果想调用sum方法就没有了参数,在scala中,只会将min函数移除出栈内存,而参数x,y,z会保留,供sum函数使用,这样延长了x,y,z变量的生命周期,这样使用函数嵌套延长变量生命周期的方式叫做函数的闭包。

    闭包的应用练习如下,求两个数的积,如果有必要添加第三个数来求积。

    scala> def product(x:Int,y:Int):Int => Int={
         | println("两个数的积为:"+x*y)
         |  def add(z:Int):Int={
         |  println("三个数的积为:"+x*y*z)
         |  x*y*z
         |  }
         | add _
         | }
    product: (x: Int, y: Int)Int => Int
    
    scala> product(3,4)
    两个数的积为:12
    res19: Int => Int = <function1>
    
    scala> product(3,4)(5)
    两个数的积为:12
    三个数的积为:60
    res20: Int = 60
    
    
    (2)柯理化

    柯理化是闭包的一种简化形式,写法更加简洁,但是使用没有闭包灵活,必须传入指定数目参数才能执行。

    # 比较两个值的较大值
    # 1 闭包写法
    scala> def max(x:Int)={
         |  def max1(y:Int)={
         |  if (x>y) x else y
         |  }
         | max1 _
         | }
    max: (x: Int)Int => Int
    
    scala> max(1)
    res21: Int => Int = <function1>
    
    scala> max(1)(2)
    res22: Int = 2
    # 2 柯理化写法
    scala> def max2(x:Int)(y:Int)={
         | if (x>y) x else y
         | }
    max2: (x: Int)(y: Int)Int
    
    scala> max2(1)(2)
    res23: Int = 2
    
    
    (3)函数作为参数

    函数可以作为参数,这也是高阶函数的一种。

    # 函数作为参数传入
    scala> def printResult(x:Int,y:Int,f:(Int,Int)=>Int):Unit={
         | println(f(x,y))
         | }
    printResult: (x: Int, y: Int, f: (Int, Int) => Int)Unit
    # 定义函数1
    scala> def sum(x:Int,y:Int)=x+y
    sum: (x: Int, y: Int)Int
    # 定义函数2
    scala> def minus(x:Int,y:Int)=x-y
    minus: (x: Int, y: Int)Int
    # 函数作为参数传入,根据函数不同,得到的结果也不同
    scala> printResult(3,4,sum)
    7
    scala> printResult(3,4,minus)
    -1 
    
    

    函数作为参数传入,可以直接将匿名函数传入刚才定义的函数。

    scala> printResult(3,4,(x:Int,y:Int)=>x*y)
    12
    
    

    如果参数类型确定,可以省略类型。

    scala> printResult(3,4,(x,y)=>x*y)
    12
    
    

    如果参数只在匿名函数方法体中出现一次,可以用下划线来代替。

    scala> printResult(3,4,_*_)
    12
    
    

    函数的递归

    类似java和python,scala中也可以使用递归,需要注意的是递归需要指定返回值类型,因为无法通过类型自动推导。

    # 求阶乘
    scala> def getfactorial(num:Int):Int={
         | if (num==1) return 1 //不写return,会报StackOverflowError,因为执行到此处,会依然往后执行,函数使用最后一行结果作为返回
         | return num*getfactorial(num-1)
         | }
    getfactorial: (num: Int)Int
    
    scala> getfactorial(5)
    res33: Int = 120
    
    

    可变参数

    类似java中参数可以传入可变参数(使用...),scala中也可以实现,使用 " 变量类型* " 来表示任意多个可变参数。

    # 求和,参数变长
    scala> def sum(arr:Int*)={
         | var sum=0
         | for(i <- arr) sum+=i # 增强型for循环
         | sum
         | }
    sum: (arr: Int*)Int
    scala> sum(1,2,3,4,5,6,7,8,9,10)
    res35: Int = 55
    
    
    

    函数中可设定默认值

    函数中可以给参数默认值,如果方法没有传入此参数就按默认值来计算。

    scala> def getOffPrice(money:Double,offFactor:Double=1)=money*offFactor
    getOffPrice: (money: Double, offFactor: Double)Double
    # 按默认值计算
    scala> getOffPrice(100)
    res36: Double = 100.0
    # 按给定值计算
    scala> getOffPrice(100,0.8)
    res37: Double = 80.0
    
    

    懒值

    scala中设置懒值,可以让懒值加载时才执行。

    package boe.com.clyang.function
    
    /**
     * 懒值
     * 加载时才真的运行
     */
    object LazyValue {
    
      def sum(i:Int,j:Int)={
        println("sum is running~~~")
        i+j
      }
    
      def main(args: Array[String]): Unit = {
        var i=3
        var j=4
        //将sum求和设置为懒值
        lazy val result=sum(i,j)
    
        # 线程等待3秒,自动回来,模拟这里有很多的代码
        println("sleeping")
        Thread.sleep(3000)
    
        //只有这里真正加载时才执行sum求和
        println(result)
    
      }
    }
    
    

    控制台结果,可以看出虽然sum方法在写在前面,但是因为设置了懒加载,在等待3秒后,println打印时才真正加载执行。

    sleeping
    sum is running~~~
    7
    
    

    以上,是scala入门基础知识,记录一下备用。

    参考资料:

    (1)菜鸟教程

    (2)scala官网

    (3)https://blog.csdn.net/qq_31573519/article/details/82749188 守护循环

  • 相关阅读:
    springmvc中@PathVariable和@RequestParam的区别
    Spring MVC 学习总结(一)——MVC概要与环境配置
    web中session与序列化的问题
    EL表达式
    JSTL自定义标签
    [c++][语言语法]stringstream iostream ifstream
    [C++][语言语法]标准C++中的string类的用法总结
    [数据库]数据库查询语句
    [c++][语言语法]函数模板和模板函数 及参数类型的运行时判断
    机器学习算法汇总
  • 原文地址:https://www.cnblogs.com/youngchaolin/p/12306877.html
Copyright © 2011-2022 走看看