【Scala---02】Scala 基础 『 变量和数据类型 | 控制语句 | 函数式编程』

1. 变量和数据类型

1.1 变量和常量

  1. 语法

    1. 定义变量:var 变量名:数据类型 = 值 【相当于Java 没有 用final关键字修饰】
    2. 定义常量:val 常量名:数据类型 = 值 【相当于Java final关键字修饰】
  2. 注意点

    // 1. 常量值无法修改
    val NAME:String = "张三"
    NAME = "李四”  // 报错
    
    // 2. Scala是强引用,因此不可为变量赋不同数据类型的值
    var age:int = 18
    age = "张三"  // 不可将字符串赋值给整型变量
    
    // 3. 声明 常量、变量时,数据类型可以省略,但是初始值不可省略。这样可以自动推断数据类型
    	// 自动推断
    	// 值为整型:int
    	// 值为小数:double
    	// 值为字符串:String
    val NAME = "张三"   // 会自动推断变量类型
    
    // 4. 关于对象:
    	// (1) var修饰的对象可以修改指向,而val修饰的对象不可以修改修改指向
    	// (2) 对象的属性是否可以修改,取决于属性是用var还是val修饰
    	val PERSON = Person()
    	PERSON = Person()   // 错误
    
  • 建议:能用常量,就不要用变量
  • 标识符的命名规范
    在这里插入图片描述

1.2 字符串

  1. 字符串拼接

    1. 通过+号连接

      println("hello" + "world")
      
    2. 重复字符串拼接

      println("linhailinhai" * 200)
      
  2. 字符串输出

    1. 通过%传值:和c语言一样
      var name = "张三"
      var age = 18
      printf("name: %s age: %d\n", name, age)  // print()不换行,println()换行
      
    2. s打头,然后通过$获取变量值
      var name = "张三"
      var age = 18
      printf(s"name: ${name} age: ${age}\n")
      
  3. 三引号字符串:方便写SQL

    // s打头,每个行用 | ,最后.stripMargin 
    val sql = s"""
    	| select *
    	| from table
    	| where name = ${name}
    	| 	and age > ${num}
    """
    // stripMargin 的作用就是忽略空格、|等符号,也就是说只剩下SQL语句
    

1.3 数据类型

Scala中没有基本数据类型,只有引用数据类型:分为基本引用数据类型 和 非基本引用数据类型两类

  1. 包含Java的9种基本引用数据类型 (Byte, Short, Char, Integer❌ Int✅, Long, Float, Double, Boolean, String)
  2. Unit 相当于 Java中的 void
  3. 常见父类 / 子类:
    1. Any类,是所有类的父类,等价于Java的Object
    2. AnyVal 类是 9种基本引用数据类型 + Unit 的父类。
    3. AnyRef类是所有非基本引用数据类型的父类。
    4. Nothing是所有引用数据类型的子类。应用场景:一个函数没有明确返回值时指定
      在这里插入图片描述

细节:

  1. 引用数据类型的默认值:和Java一样
    1. 9种基本引用数据类型:0、false
    2. 非基本引用数据类型:null
  2. 给变量赋值时,可以不指定数据类型,会自动分配
    1. 字符串默认是String。比如:val name = "zhangsan"
    2. 整数默认是Int。比如:val age = 15
    3. 小数默认是Double。比如:val money = 150.0
    4. 字符默认是Char。比如:val c = 'x'
    5. 布尔默认是Boolean。比如:val is_find = false
  3. Nothing vs Unit vs Null
    1. Unit 用于方法无返回值的情况
    2. Nothing 用于非方法的代码块无返回值的情况
    3. Null 是非基本引用对象没有赋值的默认值
      在这里插入图片描述
  4. 集合类型的泛型很容易和Java中的数组弄混:
    • Java中的数组:int[] a = {0, 1, 2};
    • Scala中的泛型:Array[Int] a = Array(0, 1, 2) // 使用伴生对象创建数组
    // 访问`Array`:
    val arr = new Array(10, 20, 30)
    println(arr(0)) // 输出第一个元素10
    

1.4 代码块

在Scala中:

  1. 所有代码都是代码块
  2. 最后一行代码的结果就是返回值
object Test {
	def main(args: Array[String]): Unit = {	
	// 所有的代码都是代码块
	   // 表示运行一段代码  同时将最后一行的结果作为返回值
	   val i: Int = {
	     println("我是代码块")
	     10 + 10
	   }
	
	   // 代码块为1行的时候  大括号可以省略
	   val i1: Int = 10 + 10
	
	   // 如果代码块没有计算结果  返回类型是unit
	   val unit: Unit = {
	     println("hello")
	     println("我是代码块")
	   }
	
	
	   // 当代码块没办法完成计算的时候  返回值类型为nothing
	   // val value: Nothing = {
	   //	 println("hello")
	   //	 throw new RuntimeException
	   // }
	}
}

1.5 强制转换

调用方法进行强制转换:

// Java  :  
int num = (int)2.5

// Scala :  
var num : Int = 2.7.toInt

1.6 运算符

和Java一样:
在这里插入图片描述

1.7 == 与 equals

  • Scala中==与equals相同,都是比较内容是否相等
  • 如果要比较地址是否相同,用.eq()方法
    def main(args: Array[String]): Unit = {
    
        val s1 = "abc"
    
        val s2 = new String("abc")
    
        println(s1 == s2)
        println(s1.eq(s2))
    }
    
    输出结果:
    true
    false
    

2. 控制语句

2.1 分支语句

在Scala中,有if、if-else、if-else if-else,三元运算符,没有switch。用法和Java一样。

2.2 循环语句

(1)for循环

  1. 基本功能

    // 1. 左闭右闭 []
    for(i <- 1 to 10) {
    }
    
    // 2. 左闭右开 [)
    for(i <- 1 until 10) {
    }
    
    // 3. 循环步长
    for(i <- 1 to 10 by 2) { // 步长为2,故结果为:1 3 5 7 9
    }
    
    // 4. for-each
    for(i <- 集合对象){
    }
    
  2. 循环守卫

    for(i <- 1 to 10 if i != 5) { // 排除5
    }
    
  3. 一个for循环内定义多个变量

    for(i <- 1 to 4; j <- 1 to 5) {
    } 
    

(2)while/do-while循环

可以,前者是现在判断后执行;后者是先执行后帕顿。但是不推荐使用,推荐后面使用函数式编程的递归方法

(3)循环中断

Scala内置控制结构特地去掉了break和continue,是为了更好的适应 函数式编程,推荐使用函数式的风格解决break和continue的功能,而不是一个关键字。

// 使用Breaks.breakable()方法来实现中断
// 使用Breaks.break()方法代替java中的break关键字
Breaks.breakable(
	for(i <- 1 to 10) {
		if(i == 3)
			Breaks.break() -- 写就是中断,不写就是continue
	}
)

(4)yield关键字结合for循环使用

yield 的作用是把每次迭代生成的值封装到一个集合中,如果把yield去掉那返回给C的值就为Unit。
在这里插入图片描述

2.3 switch

switch 用模式匹配 match 代替:

object TestMatchCase {

  def main(args: Array[String]): Unit = {

    var a: Int = 10
    var b: Int = 20
    var operator: Char = 'd'

    var result = operator match {
      case '+' => a + b
      case '-' => a - b
      case '*' => a * b
      case '/' => a / b
      case _ => "illegal"
    }

    println(result)
  }
}

在这里插入图片描述

注意:在调用算子时,可以在里面直接写模式匹配。比如:
在这里插入图片描述

(1) 匹配类型

object Test02_MatchValue {

  def main(args: Array[String]): Unit = {

    // 匹配类型
    def func2(x:Any):String ={
      x match {
        case i:Int => "整数"
        case c:Char => "字符"
        case s:String => "字符串"
        case _ => "其他"
      }
    }

    println(func2(1515))
    println(func2('\t'))
    println(func2("1515"))
  }
}

(2) 匹配元组

object TestMatchTuple {

  def main(args: Array[String]): Unit = {

    //对一个元组集合进行遍历
    for (tuple <- Array((0, 1), (1, 0), (1, 1), (1, 0, 2))) {

      val result = tuple match {
        case (0, _) => "0 ..." //是第一个元素是0的元组
        case (y, 0) => "" + y + "0" // 匹配后一个元素是0的对偶元组
        case (a, b) => "" + a + " " + b
        case _ => "something else" //默认

      }
      println(result)
    }
  }
}

(3) 匹配对象及样例类

object Test05_MatchObject {
  def main(args: Array[String]): Unit = {
    val zhangsan = new Person05("zhangsan", 18)

    zhangsan match {
      case Person05("zhangsan",18) => println("找到张三啦")
      case _ => println("你不是zhangsan")
    }
  }
}


class Person05 (val name:String,var age:Int){

}

object Person05{
  // 创建对象的方法
  def apply(name: String, age: Int): Person05 = new Person05(name, age)

  // 解析对象的方法
  def unapply(arg: Person05): Option[(String, Int)] = {
    // 如果解析的参数为null
    if (arg == null ) None else Some((arg.name,arg.age))
  }
}

3. 方法与函数

3.1 方法

在Scala中万物皆方法。

  1. 所有的运算符本质上是方法。比如查看Int
    在这里插入图片描述
    可以看到类中定义了很多以运算符命名的方法
    在这里插入图片描述
    因此,以下两种方法是等价的
     val a = 1 + 2
     val a = 1.+(2)
    
  2. 反过来,可以定义这样的方法,并调用
    1. 例子1

      object Cal {
          def say(x:Int):Int = x
      }
      
      object Main {
          def main(args: Array[String]): Unit = {
              // 1. 用 类.方法名(参数列表) 形式调用方法
              var result1 = Cal.say(3)
      
              // 2. 用 类 方法 参数列表 形式调用方法
              var result2 = Cal say (3)  
              var result3 = Cal say 3    // 如果参数列表只有一个值,括号是可以省略的
          }
      }
      
    2. 例子2

      object Main {
      
          def say(x:Int):Int = x
      
          def main(args: Array[String]): Unit = {
              // 1. 用 类.方法名(参数列表) 形式调用方法
              var result1 = this.say(3)
      
              // 2. 用 类 方法 参数列表 形式调用方法
              var result2 = this say (3)  // 如果参数列表只有一个值,括号是可以省略的
              var result3 = this say 3
          }
      }
      

3.2 函数

3. 函数式编程

  • 函数式编程思想:① y = f(x),重要的是映射关系。② 当做数学题,故推荐使用val,因为不变值在分布式上计算后不会产生歧义
  • 定义函数有两种形式:
    1. def形式【一般定义方法时,使用这种形态】
    2. lambda表达式形式 【一般定义在方法内定义函数时,使用这种形态】
      在这里插入图片描述

3.1 函数的第一种形态

(1) 定义函数

在这里插入图片描述

注意:一般定义方法时,使用这种形态。(方法是特殊的函数)

(2) 函数声明

在这里插入图片描述

object TestFunctionDeclare {
    // 函数1:无参,无返回值
    def test(): Unit = {
        println("无参,无返回值")
    }

    // 函数2:无参,有返回值
    def test2(): String = {
        return "无参,有返回值"
    }

    // 函数3:有参,无返回值
    def test3(s: String): Unit = {
        println(s)
    }

    // 函数4:有参,有返回值
    def test4(s: String): String = {
        return s + "有参,有返回值"
    }

    // 函数5:多参,无返回值
    def test5(name: String, age: Int): Unit = {
        println(s"$name, $age")
    }
}

(3) 函数参数

object Test03_FunArgs {

  def main(args: Array[String]): Unit = {

    // (1)可变参数:在类型后面加*号
    def sayHi(names:String*):Unit = {
      println(s"hi $names")
    }

    sayHi()
    sayHi("linhai")
    sayHi("linhai","jinlian")

    // (2)可变参数必须在参数列表的最后
    def sayHi1(sex: String,names:String*):Unit = {
      println(s"hi $names")
    }

    // (3)参数默认值
    def sayHi2(name:String = "linhai"):Unit = {
      println(s"hi ${name}")
    }

    sayHi2("linhai")
    sayHi2()


    // (4)默认值参数在使用的时候 可以不在最后
    def sayHi3( name:String = "linhai" , age:Int):Unit = {
      println(s"hi ${name}")
}

    // (5)带名参数:指调用方法时,指定传参顺序
    sayHi3(age = 10, name = "niu")
  }
}

(4) 至简原则

在这里插入图片描述

注意:方法最后一行的return可以省略,但是除此之外都不能省略。比如
在这里插入图片描述

object Test04_FuncSimply {

  def main(args: Array[String]): Unit = {

    //(1)return可以省略,Scala会使用方法体的最后一行代码作为返回值
    def func1(x: Int, y: Int): Int = {
		x + y
    }

    // (2)如果方法体只有一行代码,可以省略花括号
    def func2(x: Int, y: Int): Int = x + y

    //(3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)
    //     此时,函数就变为了数学表达式的形式:f(x, y) = x + y
    def func3(x: Int, y: Int) = x + y

    //(4)如果有return,则不能省略返回值类型,必须指定
    def func4(x: Int, y: Int): Int = {
    	if (x < 20) {
    		return x + y
    	}
    	2 * x + 3 * y
    }

    //(5)如果方法明确声明unit,那么即使函数体中使用return关键字也不起作用
    def func5(x: Int, y: Int): Unit = return x + y

    //(6)Scala如果期望是无返回值类型,可以省略等号
    def func6(x: Int, y: Int) {
		println(x + y)
    }

    // (7)如果方法无参,但是声明了参数列表,那么调用时,小括号,可加可不加
    def func7(): Unit = {
      println("hello")
    }

    // (8)如果方法没有参数列表,那么小括号可以省略,调用时小括号必须省略
    def func8 {
		println("hello")
    }

	// (9)如果不关心函数名,只关心映射逻辑,就会变为lambda表达式
	(x:Int, y:Int) => {println(x + y)}
	val func = (x:Int, y:Int) => {println(x + y)}  // 如果要设置函数名可以这样。此时,func就是函数名
  }
}

3.2 函数的第二种形态

3.3 高阶函数

  • 高阶函数:参数或返回值为函数的函数(或方法)称为高阶函数

  • 函数作为参数传递:
    在这里插入图片描述

    object TestFunction {
    
        def main(args: Array[String]): Unit = {
            //制作一个计算器
            val calculator = (a: Int, b: Int, operater: (Int, Int) => Int) => { //高阶函数————函数作为参数
                operater(a, b)
            }
    
            //函数————求和
            val plus = (x: Int, y: Int) => {
                x + y
            }
    
            //方法————求积
            val multiply = (x: Int, y: Int) => {
                x * y
            }
    
            //函数作为参数
            println(calculator(2, 3, plus))
            println(calculator(2, 3, multiply))
        }
    }
    
  • 函数作为返回值传递
    在这里插入图片描述

    object TestFunction {
        def main(args: Array[String]): Unit = {
    	    val func1 = (x: Int) => {
                val func2 = (y: Int) => x + y
                func2
                // 或者直接返回:(y: Int) => x + y
            }
        }
    }
    

一看到 =>,就要想到这是表示函数。

3.4 函数柯里化&闭包

  • 闭包:内层函数用到了外层函数变量,如果直接调用内层函数会取不到外层函数的这个变量值。此时,内层函数(万物皆对象,函数也是对象)的堆中的对象会保留一份引用到外层函数的值。
    闭包参考链接

  • 函数柯里化:将一个接收多个参数的函数转化成一个一个接受参数的函数过程,可以简单的理解为一种特殊的参数列表声明方式。函数柯里化

    object TestFunction {
    	
      val sum = (x: Int, y: Int, z: Int) => x + y + z
    	
      // 函数柯里化的底层逻辑:本质是将函数作为返回值
      val sum1 = (x: Int) => {
        y: Int => {  // 匿名函数
          z: Int => { // 匿名函数
            x + y + z
          }
        }
      }
    
      // 函数柯里化的另一种简单表达
      val sum2 = (x: Int) => (y: Int) => (z: Int) => x + y + z
    
      // 方法也有函数柯里化
      def sum3(x: Int)(y: Int)(z: Int) = x + y + z
      
      def main(args: Array[String]): Unit = {
        sum(1, 2, 3)
        sum1(1)(2)(3) // sum1(1)调用完后,返回一个函数; sum1(1)(2)是调用返回的函数; .......
        sum2(1)(2)(3)
        sum3(1)(2)(3)
      }
    }
    

3.5 递归 & 尾递归

  1. 递归与Java中的递归一样:前面知道scala的方法返回值是可以省略的,默认分配返回值类型,但是 如果方法是递归方法,则必须指定方法的返回值类型,否则会报错

    object Test{
        def main(args: Array[String]): Unit = {
            // 实现阶乘
            def fact(n : Int) : Int = {  // 必须指名方法的返回值类型
                // 跳出递归
                if(n == 1) return 1
                // 递归逻辑
                n * fact(n - 1)
            }
            // 调用阶乘方法
            println(fact(5))
        }
    }
    
  2. 尾递归:递归是将每次调用函数/方法会压入到栈中,是累计使用资源,容易造成栈溢出;而尾递归是覆盖使用资源,不会造成栈溢出。所以,尾递归资源利用率更加高。尾递归参考链接

    一般支持函数式编程语言都支持尾递归;但是Java不支持尾递归。

4. 补充

4.1 访问元祖元素

变量名._数字    
比如:x._1 表示访问x的第一个元素

4.2 =>的含义

https://blog.csdn.net/qq_43546676/article/details/130992479

4.3 下划线的使用总结

https://blog.csdn.net/qq_43546676/article/details/130874779

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ElegantCodingWH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值