Scala语法从入门到高级运用

这篇博客详细介绍了Scala语言,包括其特点、函数式编程、安装教程、编程规范和类型体系。重点讲解了集合框架,如Array、List、Set和Map的使用,以及高阶函数、类型结构和隐式操作。同时,涵盖了泛型机制、模式匹配和通信机制等核心概念。
摘要由CSDN通过智能技术生成

目录

1、scala语言特点

2、函数式编程

3、scala的安装

4、scala语言的简介

5、scala编程语言的规范

6、scala的类型体系(重点!)

7、变量的用法:

8、数值类型

9、类型转换

10、常用的运算符

11、流程控制语句

12方法与函数

方法的总结:

方法和函数的总结

13、SCALA的集合框架(重点)

不可变List的应用

4.3.3 可变List的应用

遍历Map

使用其他子类型获取对象

14 类型结构(重要)

[B <: A] 的应用

[B >: A]的应用

15高阶函数

函数作为参数传递

16 隐式操作

17 通信机制


题外话:

为什么要学习Scala语言?
Scala语言是Spark语言的基础,不会scala就无法入门spark语言。spark语言是大数据开发必备的语言,通过RDD运算对离线数据或者微批次数据进行处理。学大数据就一定要学Spark!
复制代码

1、scala语言特点

1. 面向对象的语言
2. 面向函数式编程的语言
3. 静态的语言
4. 扩展性良好
5. 支持Actor并发模型(多线程)
复制代码

2、函数式编程

1. 函数式编程,也是一种编程思想
2. 纯粹的函数式编程语言编写的函数没有变量,输入的值确定,那么输出的结果是确定的。没有副作用
3. 可以使用变量的程序设计语言,是有副作用
	一个带有副作用的函数不仅有一个返回值,还可能做了:
      修改一个变量
      直接修改数据结构
      设置一个对象的成员
      打印到终端或者读取用户输入
      读取或写入一个文件
      在屏幕上绘画
  	  抛出一个异常或以一个错误终止
4. 函数是一等公民、是有返回值的,和基本类型的值、对象的地位是一样的,可以直接拿来使用。
5. 以表达式为中心  
复制代码

函数式编程的优势:

- 代码简洁,开发速度快
- 接近自然语言,易理解
- 易于代码管理
- 适合并发编程
- 适用于热升级
复制代码

3、scala的安装

1)上传、解压、更名
[root@qianfeng01 ~]# tar -xvf scala-2.11.8.tar -C /usr/java
[root@qianfeng01 ~]# cd /usr/local
[root@qianfeng01 local]# mv scala-2.11.8 scala

2)配置系统环境变量
[root@qianfeng01 local]# vi /etc/profile
........省略......
export SCALA_HOME=/usr/local/scala
export PATH=$SCALA_HOME/bin:$PATH

3)保存退出后重新加载
[root@qianfeng01 local]# source /etc/profile
4)验证
[root@qianfeng01 local]# scala -version
复制代码

4、scala语言的简介

Scala的REPL就是scala的命令行交互界面。
		R->read  表示可以接受用户的输入数据
		E->evaluate  可以计算数据
		P->print    可以打印数据
		L->loop     可以循环操作

复制代码

演示

scala> 1
res0: Int = 1           # res0  是内置提供的变量,用来存储回车后的值

scala> res0
res1: Int = 1           # 可以打印变量的值      值又存到res1里了

scala> res0+res1        # 表达式
res3: Int = 2

scala> val age:Int = 28  #使用val定义变量age 同时指定类型 并赋值
age: Int = 28

scala> 1+1*10
res4: Int = 11

scala> val  num = 34     # scala可以推断没有指定类型的变量的类型,也可以证明数字的默认类型是Int
num :Int = 34 
复制代码

上面那个是windows中安装了scala的环境,在cmd中演示的

下面这种是在windows编译。个人喜好在idea中整合scala敲。

1. 在D盘的dir目录下,创建一个hello.scala源文件,内容如下
object HelloWorld{
	def main(args:Array[String]):Unit ={
		print("you are best")
	}
}
2. 编译源文件:    语法格式:scalac  源文件名
	D:\dir> scalac hello.scala

    注意: 结果会产生两个class文件
3. 运行字节码文件:   语法格式:scala 字节码文件名(不带后缀)
	D:\dir> scala HelloWorld
复制代码

scala和idea的整合

1. file-->settings-->plugins-->搜索scala
2. 选择install,   读条
3. apply,如果有重启,那就重启
复制代码

5、scala编程语言的规范

1. 源文件扩展名(后缀)必须是.scala
2. 源文件名和里面的代码的最顶层的类名一致,区分大小写、所有源文件编码必须是 UTF-8
3. scala中的标识符要符合驼峰命名法、尽量做到见名知意(望文知意)
4. scala的语法缩进要使用空格、不要使用tab键(注意:Idea自动将tab键转成了2个空格,可以百度自行调整四个空格)
5. 单行长度不建议超出150字符、也就是不要超出可视化范围
6. 花括号的用法和java一致、该换行就换行。
7. 空行的目的,用于逻辑分组。比如  方法和成员变量之间应该多一个空行
8. 在简单的表达式上,能省略花括号就省略。
9. Scala的每句话说完,不需要使用分号,换行即可。
10. 注释风格,和java一样
	  //   单行注释
	  /*  多行注释*/
	  /** 文档注释*/
复制代码

6、scala的类型体系(重点!)

1. scala的超类(父类,基类)是Any
2. Any下有两个直接子类型,分别是AnyVal  和AnyRef
	     Byte-->Short-->Int-->Long-->Float-->Double
	            Char
	     boolean
        Unit
4. AnyRef包括了java的所有引用类型、Scala的所有集合类型、以及Scala的其他引用类型,以及Null类型
5. Nothing是Scala的所有其他类型的子类型,位于类型层次的最底层

6. Null类型只有一个实例值是null
	scala> val a = null
	a: Null = null
7. Unit和java的void相似,是一种类型,也只有一个实例()
	scala> val a = ()
	a: Unit = ()
复制代码

7、变量的用法:

1. 需要使用val和var来定义、而且必须同时使用等号,进行初始化
2. 定义变量时、可以指定类型、也可以不指定类型(scala编译器会自动推断类型)
    val  num1 = 10      scala会自动推断类型
    指定类型的写法:  val  num2:Long = 10  
3. val声明变量时、可以使用lazy修饰、还有特点就是变量不能再次赋值,相当于用了final修改该变量
4. var声明变量时,不能使用lazy修饰、变量可以再次赋值
5. 变量一旦初始化后、类型确定,不能再赋值其他类型的值
6. scala推荐使用val来定义变量,因为:
	  - 更安全
	  - 可读性更高
	  - 节省内存资源
	  
	  val 对应的单词是value,即值,常量的含义,因此可以理解为是final修饰的。实际上在转成.class时,确实是final修饰的变量
	  var 对应的单词是variable,即可变的,易变的,多变的含义。 因此对应的变量可以多次赋值。
复制代码

8、数值类型

计算所遵循的原则:
	1.  不同的数值类型计算时,需要转为同一种类型进行计算
	2.  如果是小于Int类型的两种类型计算、都转为Int类型计算
	3.  如果是其他情况的两种不同类型,那么就会转为较大类型的数据进行计算
	
数值类型有八种、可以细分如下:
整型四种:Byte  、Short 、Int、Long、 
		- 整型的默认类型是Int
		- Long的值需要添加L/l
	    - 也可以赋值16进制的数字  如: val num = [0x|0X]ffff    就是255的16进制

浮点型两种:Float、Double
		- 浮点型的默认类型是Double
		- Float的数字需要添加F/f
		- 赋值时也可以这样:   
				省略0的写法:		.512    .34F 
                科学计数法:      5.12e2   
                
字符类型:  Char
		 - 赋值时需要使用单引号,单引号里只能有且只有一个字符 
         - 也可以赋值整数、范围是0~65535
         		var  ch1 : Char = 65 
         - 也可以赋值16进制形式
         	    如:  var ch1 = '\u0041'   是字符A的unicode编码
         	
布尔类型:  Boolean
		- 只有两个值,true和false,用于判断条件是否成立
		- 一般用于分支或者是循环结构中
复制代码

String类型

1.  Scala的String的本质就是java的String
	 “zhangsan”.getClass.toString
2.  赋值使用双引号
3. 也可以使用三引号,进行换行赋值
   var  name = """
   			|zhangsan
   			|lisi
   			|"""	
复制代码

Option类型

用来表示一个值是可选的,实际上就是有值和无值两种。
有值的话,是Some(value)
无值的话,就是None

总之:Option类型就两个值:Some(value)、None
复制代码

9、类型转换

1. 数值类型
	-- 隐式转换:  小类型的变量赋值给大类型的变量,会自动在前面添加相应位数的0或1
	              比如:   var  a: Byte = 10       二进制: 0000 1010
	                      var  b: Short = a       二进制: 0000 0000 0000 1010
	                      b变量是16位, 此时是Byte类型的10在前面自动添加8个0,进行补全
	-- 强制转换:  大类型的变量赋值给小类型的变量时,必须强制转换  
    	        java中语法:  小类型名   变量名  = (小类型名)大类型变量
    	        scala中,必须调用相关的转换方法,如
    	                   val num1 = 10;
    	                   val num2:Short = num1.toShort   
2. 数值类型与字符串之间的转换
	- 数值类型转字符串,直接使用拼接符号+,拼接即可
	     var  age = 28
	     var  str = age+""          // "28"
	     var  str = age+"hello"     // "28hello"
	- 字符串转数值类型,需要掉相应的转换方法
	     var str = "28";
	     str.toInt     // 转成了Int类型的28
	     
	     注意:非纯数字的字符串无法转成数字类型,NumberFormatException
    	   
复制代码

10、常用的运算符

1. 算数运算符:  + 、- 、* 、/ 、% 
	    计算原则:  
	    	--(1) 不同类型的数据做运算时,会转成较大类型的数据,再运算
	      --(2) 两个类型都小于Int时,转成Int类型,再运算 
        比如:  18.0/6  运算逻辑:6要先转成double的6.0, 然后和18.0做运算。结果类型是Double,所以结果是3.0 
               18/7    结果类型是Int,所以结果是2
               也可以这样理解:两个整形运算,除法符号是取整操作
                             只要有一个是浮点型,就是正常除法运算
               
2. 关系运算符: >,>=,<,<=,==,!=
		  -- 用来判断两边的数值的关系是否成立,只有两种结果,true、false
		  -- 通常用于分支结构和循环结构,充当条件
3. 赋值运算符: = 、+=、-=、*=、/=、%=
4. 短路逻辑运算符: 一般用于连接多个关系表达式的,结果也是true、false
			&&  :  一假则假,全真为真  
			||  :   一真则真, 全假为假
			!  :   非真即假,非假即真
			
			短路逻辑:  当前面的条件可以确定结果后,后面的条件不再执行
5. 位运算符  :    1为 真   0为假
		&  : 与   口诀:  一0则0,全1为1            
		|  : 或   口诀:  有1则1,全0为0
		^  : 异或  口诀:  相同为0,不同为1
		>> : 有符号右移, 原来是正,结果就是正,原来是负,结果就是负数 
		<< :有符号左移, 原来是正,结果就是正,原来是负,结果就是负数
		
		     有符号移动时,正数高位补0,负数高位补1
		>>>:无符号右移: 表示所有二进制位上的数向右移动,高位补0
复制代码

11、流程控制语句

11.1 Scala表达式(重要)

1. 在scala中,你所看到的完整的语句,都是一个表达式
2. 只要是表达式,那么一定有返回值
    比如:
          a + b    返回的就是两个变量的和
          println("aaaa")  打印语句也是一个表达式,返回Unit类型,值为()
          throw new Exception();  也是一个表达式,返回Nothing
3. 常见的表达式:
	- 块表达式
	- if表达式
	- 循环表达式
	- 异常表达式
	- Actor并发模型表达式
4. 块表达式:
	-- 即{}整体,有返回值,返回值为{}中的最后一个表达式的返回值
5. 赋值表达式
	-- 有返回值,返回值为Unit类型
	scala> var c = (b+=a)
		c: Unit = ()
复制代码

11.2 分支结构

if分支的语法与java语法一样,有以下三种写法:
1. 只有一条分支的写法
	if(条件表达式){
		逻辑体
	}
2. 两条分支带else的写法
	if(条件表达式){
		逻辑体
	}else{
		逻辑体
	}
3. 带else if的写法
	if(条件表达式){
		逻辑体
	}else if(条件表达式){
		逻辑体
	}else if(条件表达式){
	
	}.....
	
小贴士:
	 1. 只要某一个分支的条件表达式成立,那么剩下的分支直接跳过不执行。
	 2. 如果带有else模块,那么一定会执行其中一条分支,如果不带else,可能一条分支都不执行。
	 3. 针对于scala来说,if分支结构本身就是表达式,表达式的值是结构中所有的花括号的最后一个表达式的共同的父类
复制代码

11.3循环结构

说明:
1. 循环结构本身也是一个表达式,有值。
2. 循环结构的种类:
	-- while  : 条件成立时,才会执行循环体 
	-- do-while  :先执行一次循环体,再判断条件是否成立
	-- for循环: 

复制代码

11.3.1while和do-while

while(条件表达式){
	循环体
}

do{

}while(条件表达式)
复制代码

练习

package com.qf.scala.day03
/**
 * 计算100以内的奇数之和
 */
object _02WhileDemo {
    def main(args: Array[String]): Unit = {
        var num = 1;
        var sum = 0;
        while(num<100){
            if(num%2==1){
                sum+=num;
            }
            num+=1;
        }
        println(sum)
    }
}

复制代码
package com.qf.scala.day03

import scala.io.StdIn

object _03DoWhileDemo {
    def main(args: Array[String]): Unit = {
        var password = "";
        do{
            println("请输入密码")
            password = StdIn.readLine();
        }while(password!="123456")
        println("密码正确")
    }
}
复制代码

11.3.2 for循环

说明:
循环时的范围表示方式,有两种,分别是使用to或者是until
1. to的写法:
	1 to  10
	1.to(10)    
	
	特点: 包含10.   是一个闭区间
2. until的写法
	1 until 10 
	1.until(10)
	
	特点: 不包含10,  是一个左闭右开区间
复制代码
for循环的语法结构
小贴士:  java中的for循环结构有两种写法
		 一种是经典for循环写法  :       
		 		for(循环因子的声明和初始化;循环条件;向着循环结束的方向变化的表达式){}
         一种是增强for循环写法
         		for(类型名  变量名:集合|数组){}
注意:scala里的for循环,相当于java中的增强for循环写法

for( 变量名 <- 集合|数组|Range|表达式 ){
	循环体
}
复制代码

练习

package com.qf.scala.day03

object _04ForDemo {
    def main(args: Array[String]): Unit = {
        //练习1:   打印 1 到 10
        for(num <- 1 to 10){
            print(num+"\t")
        }
        println
        for(num <- 1 until  11){
            print(num+"\t")
        }
        println
        //练习2: 遍历数组
        val names = Array("zhangsan","lisi","wangwu","zhaoliu")
        for(name <- names){
            println(name)
        }
        //练习3: 打印一个字符串中的所有的字符
        val str = "helloworld"
        for( i <- 0 until  str.length){
            print(str(i)+" ")
        }
        println
        //练习4:  计算1到10的和
        var sum = 0;
        for(i<-1 to 10){
            sum+=i;
        }
        println(sum)
        //练习5:  
        //  for循环本身就是一个表达式,因此有值,
        //  值比较特殊,是一个Vector集合, 比如循环10次,则是10个循环的最后一行的值的集合
        //  那么如何获取这个集合的值, 需要使用yield,
        //  yield的位置位于{}的前面,小括号的后面
        //  而下面的循环结构的最后一行,返回的都是(),因此集合里有10个()
        var sum1 = 0;
        val result = for(i<-1 to 10) yield{
            sum1+=i;
        }
        //遍历for循环的结果
        for(i<-result){
            println(i)
        }
    }
}
复制代码

for循环的多层嵌套

package com.qf.scala.day03

/**
 * for循环可以进行嵌套
 */
object _05ForDemo {
    def main(args: Array[String]): Unit = {
        /**
         * 练习1:  打印
         *              *****
         *              *****
         *              *****
         *              *****
         */
        for(i<- 1 to 4){
            for(j<- 1 to 5){
                print("*")
            }
            println
        }
        /**
         * 练习1:  打印
         *              *
         *              **
         *              ***
         *              ****
         *              *****
         */
        for(i <- 1 to 5){
            for(j <- 1 to i){
                print("*")
            }
            println
        }

        /**
         * 练习3: 打印乘法口诀表
         */
        for(i <- 1 to 9){
            for(j <- 1 to i){
                print(i+"*"+j+"="+i*j+"\t")
            }
            println
        }
    }
}
复制代码

多层简写

package com.qf.scala.day03

/**
 * for循环可以进行嵌套
 */
object _06ForDemoSimple {
    def main(args: Array[String]): Unit = {
        /**
         * 练习1:  打印
         *              *****
         *              *****
         *              *****
         *              *****
         */
        for(i<- 1 to 4;j<- 1 to 5){
            print("*")
            if(j==5){
                println
            }
        }

        /**
         * 练习1:  打印
         *              *
         *              **
         *              ***
         *              ****
         *              *****
         */
        for(i <- 1 to 5;j <- 1 to i){
            print("*")
            if(i==j){
                println
            }
        }

        /**
         * 练习3: 打印乘法口诀表
         */
        for(i <- 1 to 9;j <- 1 to i){
            print(i+"*"+j+"="+i*j+"\t")
            if(i==j){
                println
            }
        }

        /**
         * 练习4: 打印10次10以内的所有奇数
         */
        for( i <- 1 to 10;j <- 1 to 10;if j%2==1){
               print(j+" ")
        }
    }
}

复制代码

循环结构的终止

说明:java中的循环结构可以使用break,表示结束循环结构,continue结束当次循环,
特殊情况:也可以使用return来结束整个方法

那么,scala中也可以使用以下方式来结束循环:
1. 循环条件 , 就是控制循环的条件表达式
2. return关键字:   注意,该方式会结束整个方法
3. break:   但是需要配合breakable语句块来使用
复制代码

练习:

package com.qf.scala.day03
import scala.util.control.Breaks._
object _07ForDemo {
    def main(args: Array[String]): Unit = {
        println("-------练习1:------------")
        // 使用循环条件来结束循环
        var i = 0;
        while(i<10){
           println(i);
           i += 1
        }
        println("-------练习2:------------")
        // 使用return 关键字来结束循环,注意,会结束整个方法
        // 当num等于5时,结束循环结构
//        for( num <- 1 to 10){
//            println(num)
//            if(num==5){
//                return
//            }
//        }
//        println("-------over------------")
        println("-------练习3:------------")
        /**
         * 使用break 来结束循环结构, 需要配合breakable语句块
         * 练习: 当num等于5,结束循环
         */
        breakable{
            for( num <- 1 to 10){
                println(num)
                if(num==5){
                    break
                }
            }
        }

        println("-------练习4:使用break来表达continue的用法------------")
        /**
         * 练习: 当num等于5时,跳过,不打印
         */
        for( num <- 1 to 10){
            breakable{
                if(num==5){
                    break
                }
                println(num)
            }
        }
    }
}
复制代码

11.3.3字符串插值器

字符串插值器的应用, 功能是让字符串中的变量生效,换成变量的值
 s:  就是让字符串中的变量生效
  f: 除了有s功能外,还具有格式化的效果
  %[Num]s: 对字符串进行右对齐,左补空格,总长度为Num
  %[Num]d: 对整形进行右对齐,左补空格,总长度为Num
  %[.Num]f:对浮点数进行保留Num个小数位。
  raw: 除了具有s功能外,其他任何字符都被当做普通字符输出  \t\n\s    和lua的[[....]]  以及xml里的<![CDATA[  ]]>功能一样
 
  注意: 变量名前需要添加$variableName符号,或者使${variableName}
复制代码

代码

package com.qf.scala.day03

object _08Interpolation {
    def main(args: Array[String]): Unit = {
        var name = "michael"
        var age = 34
        var salary = 55555.1234;
        //java中一般使用+拼接
        println("有一个帅哥叫"+name+",他的年龄是"+age);
        //使用scala的插值器 s
        println(s"有一个帅哥叫${name},他的年龄是${age}");
        //使用scala的插值器 f
        println(f"有一个帅哥叫$name%10s,他的年龄是$age%10.2f,他的工资是$salary%.2f");
        println(f"有一个帅哥叫$name%10s,他的年龄是$age%10d,她的工资是$salary%.2f");
        //使用raw插值器
        println("有一个帅哥叫$name,\t他的年龄使$age")
        println(raw"有一个帅哥叫$name,\t他的年龄使$age")
    }
}

复制代码

11.3.4文件IO

用来读写磁盘或者使网络上的字符

package com.qf.scala.day03

import scala.io.Source

object _09ScalaIO {
    def main(args: Array[String]): Unit = {
        println("----------练习1: 读取文件,按照字符进行输出----------");
        //读取磁盘上的文件,返回的是一个字符迭代器
        var file1 = Source.fromFile("D:/input/dept.txt");
        for(ch <- file1){
            print(ch)   //打印的使每一个字符
        }

        println("----------练习2: 读取文件,按照行进行输出----------");
        //读取磁盘上的文件,返回的是一个字符迭代器
        var file2 =  Source.fromFile("D:/input/dept.txt");
        //调用getLines()方法,返回多行的迭代器
        var lines = file2.getLines()
        for(line <- lines){
            println(line)
        }
        //读取磁盘上的文件,返回的是一个字符迭代器
        println("---------练习3:测试mkString方法---------------")
        var file3 =  Source.fromFile("D:/input/dept.txt");
        /**
         * mkString: 该方法的作用是将数组或者集合中的元素拼接到一起。
         * 重载方法mkString(x:String): 该方法的作用是将数组或者集合中的元素使用x拼接到一起。
         */
        println(file3.mkString)
        // 也可以使用将非空迭代器变成数组类型
        var a = file3.getLines().toArray
        for(ele <- a){
            println(ele)
        }
        println("----------读取文件,按照单词进行输出----------");
        var file4 =  Source.fromFile("D:/input/dept.txt");  // 字符迭代器
        var lines1 = file4.getLines();
        for(line <- lines1){
            var words = line.mkString.split(",")   //切出来的是多个单词
            for(word <- words){
                println(word)
            }
        }

        println("----------读取文件,按照单词进行输出----------");
        var file5 =  Source.fromFile("D:/input/dept.txt");  // 字符迭代器
        val contents = file5.mkString.split(",")
        for(word <- contents)
            println(word)


        println("----------读取网络的网页信息,按照行进行输出----------");
        var contentall = Source.fromURL("http://www.baidu.com")
        var lines2 = contentall.getLines();
        for(line <- lines2){
            println(line)
        }
    }
}
复制代码

11.3.4## 正则表达式

package com.qf.scala.day03

import scala.util.matching.Regex

object _10ScalaReg {
    def main(args: Array[String]): Unit = {
        /**
         * scala中比较正规的写法,是使用Regex的类型来定义,
         * var reg = new Regex("([\\d]{18}|[\\d]{17}[X|x]|[\\d]{15})")
         * 
         * 但是scala不建议这样写,而是要使用最简单的写法,如下:
         *  var reg = "正则表达式".r
         */

        var reg = "[sS]cala".r
        var words = "scala is a simple language,java php Scala C++";
        // 找到第一个符合正则表达式的单词,如果有就返回Some(单词),如果没有返回None
        var word = reg.findFirstIn(words)
        println(word)

        var content = reg.findAllIn(words)
        for(w <- content){
            println(w)
        }

        val pattern = "(S|s)cala".r
        val str = "Scala is scalable and cool"

        println(pat
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值