Scala基础(一)

本文作为Scala基础系列的第一篇,介绍了Scala的基本概念和特性,包括数据类型、流程控制、函数定义、高阶函数、闭包与柯里化、函数递归和懒加载。Scala基于JVM,与Java有诸多相似之处,但更加强调面向对象和函数式编程。文章还提供了一些练习题,帮助读者巩固理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Scala是学习Spark的基础。比java更面向对象。

Scala基于Java的,其编译都依赖于JVM,使得Scala也能够跨平台运行。

Scala的SDK拥有Java的部分类库,以及自己的特有类库,和一些Java的封装类库。

1.下载Scala并配置环境变量。

2.创建Maven新工程,增加Scala支持。

即可开始书写Scala代码。

Scala大部分性质与Java类似

一、基础

由于已经学习过Java基础,相似部分无需过多介绍。

1.1定义变量(类型可省略,编译器会推导)

var 变量 [:类型] = 初始值
val 常量 [:类型] = 初始值

1.2标识符(基本同Java)

1.3输出字符串(前两种与Java一样,只总结特别的用法(便于写sql?))

var s =
      """
        |Select
        | name ,dept
        | from emp
        | where *****
        |""".stripMargin //默认以|为连接符

1.4键盘输入(类似Algs4(橘皮算法4)里的标准输入)

var a = StdIn.readLine()
var b = StdIn.readShort()
var c = StdIn.readDouble()

2.数据类型

Scala中一切数据都是对象,包括后文的函数,都是对象,都是Any的子类

其中数据类型分为AnyVal(数值)和AnyRef(引用)两大子类

Unit是一个数据类型,对应void 但是Unit的对象是() 而void在java只是关键字

Null也是一个类型,只有一个对象null

Nothing是所有数据类型的子类,用在一个函数没有明确返回值时使用。

对于Scala的数值类型的自动转换

(1)自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成 精度大的那种数据类型,然后再进行计算。

(2)把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动 类型转换。

(3)(byte,short)和 char 之间不会相互自动转换。

(4)byte,short,char 他们三者可以计算,在计算时首先转换为 int 类型。

3.Scala中的流程控制

if-else 需注意的是,由于定义函数的方式问题,实际上,if-else是可以有返回值的。返回值会取决于最后一行内容。

用if-else可以实现Java中的三元运算符

var res = if( ? ) conditionA else conditionB

Swtih在Scala中并不存在,需要模式匹配处理。(后续补充)

for循环  注意Scala的特殊语法即可,用法与Java基本类似,有少许扩展应用

for( i <- 1 to 5){
    println(i) //12345
}

for( i <- 1 until 5){
    println(i) //1234
}

for( i <- 1 to 3 ; j = 4 - i){
    println(i +"" + j )
}//可一次性定义i j,构成嵌套循环

var res = for( i <- 1 until 5) yield {
    i * 2    
} //res ={2,4,6,8,10}
    

4.函数定义

def sum( x : Int , y : Int ) : Int = {
    x + y
}

函数的化简原则(看得懂就行,推荐使用柯里化)

(1)return 可以省略,Scala 会使用函数体的最后一行代码作为返回值

(2)如果函数体只有一行代码,可以省略花括号

(3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)

(4)如果有 return,则不能省略返回值类型,必须指定

(5)如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用

(6)Scala 如果期望是无返回值类型,可以省略等号

(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加

(8)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略

(9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略

5.高阶函数

        5.1将值作为传递(参数为值,常规)

def f1(): Int = {
    println("f1-working")
    10
}
def f2(a: Int) = {
    println(a)
}
    f2(f1())  //f1-working  10

        5.2将函数/代码块作为参数传递

     def ff(a: String): Int = {
      println("ff-working")
      a.toInt
    }

    def ff2(op: String => Int)(s: String) = {
      println("ff2-working")
      println(op(s))
    }

    ff2(ff)("111")
    //ff2(ff())("111")   错误!这代表着你要调用ff

        5.3函数作为返回值传回

 def func(): String => Int ={
      def stoint(string: String): Int ={
        string.toInt
      }
      stoint
    }

    var aa = func()
    println(aa("11"))

        5.4匿名函数

(x:Int) => {函数体}

(1)参数的类型可以省略,会根据形参进行自动的推导

(2)类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参 数超过 1 的永远不能省略圆括号。

(3)匿名函数如果只有一行,则大括号也可以省略

(4)如果参数只出现一次,则参数省略且后面参数可以用_代替

练习 1:定义一个匿名函数,并将它作为值赋给变量 fun。函数有三个参数,类型分别为 Int,String,Char,返回值类型为 Boolean。 要求调用函数 fun(0, “”, ‘0’)得到返回值为 false,其它情况均返回 true。

(a:Int,b:String,c:Char) => {
      if ((a==0)&&(b.equals(""))&&(c.equals('0'))){
        true
      } else {
        false
      }
    }

练习 2: 定义一个函数 func,它接收一个 Int 类型的参数,返回一个函数(记作 f1)。 它返回的函数 f1,接收一个 String 类型的参数,同样返回一个函数(记作 f2)。函数 f2 接 收一个 Char 类型的参数,返回一个 Boolean 的值。 要求调用函数 func(0) (“”) (‘0’)得到返回值为 false,其它情况均返回 true。

def func(int: Int):String=>(Char=>Boolean)={
        def f1(string: String):Char=>Boolean={
          def f2(char: Char):Boolean={
            if ((int == 0) && (string.equals("")) && (char.equals('0'))) {
              true
            } else {
              false
            }
          }
          f2
        }
       f1
      }
      //柯里化
      def func(int: Int)(string: String)(char: Char) ={
        if ((int == 0) && (string.equals("")) && (char.equals('0'))) {
          true
        } else {
          false
        }
      }

6.闭包&柯里化

闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的 环境,称为闭包

函数柯里化:把一个参数列表的多个参数,变成多个参数列表。

//闭包?用于获得一个普适性和特异性的一个平衡
    //例如许多数据要进行一个加法
    def addNormal(a: Int, b: Int) = a + b

    //但是这样每次都要传入2参数  如果大多数数据一样,我们只需要针对特异性
    def addByOne(a: Int) = a + 1
    //这样的话可以有特异性,但是拓展麻烦于是兼顾特异性与普适性 嵌套

    def addByUnknown(a: Int): Int => Int = {
      def addb(b: Int): Int = {
        a + b
      }

      addb
    }
    像上述的addByUnknown,就实现了一个闭包。当我们只执行
    var addFive = addByUnknown(5) 此时我们调用了该函数,传进5 ,但是此时
    var res = addFive(123)   此时我们调用addFive时,相当于调用的addb 
    按照之前学习的java来说,此时我们调用的第一个函数已经在栈帧里消失了,那么我们传进去的5是无法到达addFive的。但是这就是函数式变成的特性,addFive访问到了外部的变量。这就是闭包。
    
    //简化
    def addByUnknown1(a: Int)(b: Int): Int = a + b //柯里化 推荐
    //实现了创造特异性函数 ,但是我们还可直接使用
    // var addFive = addByUnknown(5)    可
    // var addFive = addByUnknown1(5)   不可  因为返回值是Int,需要有个_占住b
    // var addFive = addByUnknown1(5) _  可
    // var addFive = addByUnknown2(5)    可
    // var addFive = addByUnknown2(5) _ 不可 因为其返回值是Int => Int
    // println(addFive(100))
    // var addSix =addByUnknown(6)
    // var addSix =addByUnknown1(6) _
    // var addSix =addByUnknown2(6)
    // var addSix =addByUnknown2(6) _
    // println(addSix(2))
    // println(addByUnknown1(2)(3))
    //即使用一个函数,可以创建出我们所需要的特异性函数。

7.函数递归

scala 中的递归必须声明函数返回值类型

  //递归 阶乘 正常递归
      def func0(int: Int):Int ={
        if (int == 0) {
          return 1
        }
        int *func0(int - 1)
      }
      println(func0(5))
    //尾递归
    def func1(i: Int):Int={
      @tailrec
      def loop(int: Int,res:Int):Int={
        if (int == 0){
          return res
        }
        loop(int-1,res*int)
      }
      loop(i,1)
    }
    //尾递归实现  scala的编译支持,不会StackOverflow
    //但是java并不支持,可以自己写个接口,用于支持尾递归

8.控制抽象

 //1.传值参数  只是将值传递给函数 ez
    def ff():Int = {
      println("ff work")
      10 //传值
    }
    def printff(a : Int): Unit ={
      println("a :"+a)
      println("a :"+a)
    }
    printff(ff()) //传个值
    println("==========================")
    //2.传名参数
    //(a : =>Int)  要求传进来的代码块,返回值是Int
    def function(a : =>Int): Unit ={
      println("a: "+ a)
      println("a: "+ a)
    }
    function(ff())

    function({
      println("kjs;ofij;soijf")
      2333
    })

    /*def function1(a : ()=>Int): Unit ={
      println("a: "+ a)
      println("a: "+ a)
    }*/
   // function1(ff())     错误写法,因为类型并不是一个()=>的函数

    /*
    对于传值参数 输出结果为
     ff work   a :10    a :10
    而对于传名参数
     ff work a: 10 ff work a: 10
    多调用了一次a ,因为对于传值,只执行了一次ff,启动以后,将返回值10给了printA
    而对于传名,执行了两次。相当于将a替换成ff() 那么每次提到a 就会变成ff()执行一次。
     */

9.懒加载

    lazy val res = sum(1,2)
    println("111111111111111")
    def sum(i: Int, i1: Int):Int ={
      println("sum方法执行中")
      i + i1
    }
    println(res + "    打印出res结果")

//如果没有lazy 此时是无法执行的,因为在加载res时,还没有定义sum,是无法定义的。
//同时注意  lazy只能定义val的定值

类似单例模式中的懒汉模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值