SCALA基础

SCALA基础

  • 面向对象和面向函数的集成

    !!!!一切值都是对象,一切函数都是值!!!!

  • 函数时编程,一切都是函数

  • 数学式的语法思维

——————————————————————

IDEA开发环境准备:

1、安装JDK、SCALA环境

2、IDEA安装scala插件

3、创建maven工程,创建目录,设置为root source目录

4、创建文件,后缀为scala

5、scala可以直接与java交互

——————————————————————

[TOC]

——————————————————————

1、标识符

  • 字母数字标识符:使用字母或者下划线开头,$符号在SCALA中也被看做是字母,但应该尽量避免定义$开头的变量,因为SCALA存在保留变量以$开头
  • 符号:符号标识符包含一个或多个表示符,SCALA编译时会将符号转换为$开头的变量名,如:->会被转义为$column$minus$greater,可以看出会转义为$英文单词,因此在java中调用scala程序时要使用转义后的符号

2、import导包

  • SCALA的import可以出现在任何地方,有效范围:从声明处开始到程序最后结束。
  • SCALA会默认导入java.lang._ ,scala._包,因此以scala开头的包使用时会省略包名的引用。

3、变量与常量

  • vaR定义变量

    • 变量定义时必须赋值var A:Int =1
    • 变量定义的类型可以不指定,自动推断
    • 变量空值是_下划线,定义为空值时必须指定类型var A:Char=_

    (boolean空为false,数值空为0,字符空为?)

  • vaL定义常量

    • val和def都可以定义常量,但val只初始化一次,def每次都会初始化
    • 常量的引用地址是不可改变的
    • 因为只是一层引用地址,因此使用复合类型的常量时,复合类型内部的值是可变的。

变量类型与java基本相同,但是SCALA中没有primitive基本类型,所有的值也都是对象,可以理解为只有包装类。

emmmm ,还支持很奇怪的多行字符串 """i am multiparaph string"""

4、变量类型结构

  • Any 顶级类型

    • AnyVal

      • Unit
      • Byte、Short、Int、Long、Float、Double、Char、Boolean
      • 空值:Nothing
    • AnyRef(java.lang.Object)

      • List
      • Option
      • MyClass
      • 空值:Null

5、类型别名

  • type关键字,type 别名=类型 ,类似C语言中的typedef typedef sturct{}mystruct stu

——————————————————————————————

流程语句语法

1、while循环

var i:Int=0;
while(i<100){
    println(i)
    i=i+1
}
do{
    println(i)
    i=i+1
}while(i<200)

2、for循环

val length:Int=100
for(i:Int <- 1 to length){
    println(i*100)
}
for(i:Int <- 1 to(length,step)){
    ...
}
for(i:Int <- 1 to length by step)){
    ...
}
for(i:Int <- 1 until length){
    println(i*100)
}
for(i <- 1 until(length,step)){
    ...
}
//until 和 to 都是一种函数,也可以通过i.until(length)调用
//until 和 to 创建的区间是相同的

3、中断break和breakable

  • 关于Break和Continue,要导入包才可以使用
impot import scala.util.control.Breaks.break
impot import scala.util.control.Breaks.breakable
  • breakable(语句块),内部嵌套break即可跳出本次循环
  • 卸载breakable外面的break直接跳出循环
  • breakable即可打断的语句块,相当于在循环中又嵌套了一层可被打断的语句块,将代码写在其中即可实现continue

4、多条件循环

  • 多重循环条件+分号;
val num:Int = 10;
for ( i: Int <- 1 to 10; if i%2==0;if i>5 ) 
{     
    println( i * 100 );
}yield i;
//使用 yield 将fot将具有返回值,yield中记录的是符合条件的步变量i的值的集合。
//可以看出for也是个函数

5、数组

泛型定义,中括号(java是尖括号)

数组,取值用小括号(java是中括号)

Array 不可变集合 ,元素内容可变,数组长度不可变

ArrayBuffer 可变长数组

  • 万物皆函数,因此数组也是使用的小括号()
  • 定长数组
//方式1
var a:Array[String]=new Array[String](3)
a(0)="hello"
a(1)="scala"
a(2)="world"
//方式2
var a2=Array("hello","scala")
//方式三,区间数组
var a3=Array.range(1,10,2)
//1,3,5,7,9
  • 变长数组
import scala.collection.mutable.ArrayBuffer
var arrbuf:ArrayBuffer[String]=new ArrayBuffer[String]

6、元组

  • Tuple可以包含不同类型的值,类型以实际存储的元素类型为准
  • 元组最多支持22个元素
  • 使用name._1访问name元组的第1个元素,元祖没有0号位
  • 元组的类型:元组的实际类型取决于它的分量的类型,比如的(2,"string")类型实际为 Tuple2[Int,String],而 (‘u’,’r’,”the”,1,4,”me”) 的类型为 Tuple6[Char,Char,String,Int,Int,String]
Tuple[长度](类型列表)
//元组声明方式一
var tp1 = ("Mike", "123 ABC street", 58)
println(tp1._1)
println(tp1._2)
println(tp1._3)
//迭代元组
tp1.productIterator.foreach{ i =>println("Value = " + i )}
//元组声明方式二
var tp2 = new Tuple3("Mike", "123 ABC street", 58)


//元组声明方式三
def mike = "Mike" -> 5   //键值对形式
//输出scala.Tuple2
mike.getClass
//将元组元素依次赋给三个变量
val(name, address, age) = tp1
println(name)
println(adrress)
println(age)

//元祖还可以这么玩
var yz=(1,List(2,3),"xixi")
val (id,order_id,name)=yz
//有点类似于样例类

1564123476174

7、集合Collection

1564023256574

1564023499099

1、序列Seq:List,Stack,Queue,Array

2、集合Set

3、映射Map

8、mutable和immutable不可变集合

复杂类型大都分为两类,MUTABLE和IMMUTABLE,可变的和不可变的,如ArrayBuffer就是一个可变集合,默认scala会选择不可变集合

  • 包名:scala.collection.mutable|immutable.

  • 可变集合:可以修改、添加或移除一个集合的元素

名称可变/不可变示例
Buffer mutable val buffer = scala.collection.mutable.ArrayBufferInt; buffer+=(2,3)
Array mutable val arr=Array(1,2,3)
List immutable val lst=List(1,2,3)
Map mutable val stu= Map("name" -> "Jason", "age" -> "18")
Set mutable/immutable val set=Set(1,2,3)
Vector immutable val v=Vector(1, 3, 5, 7, 11, 13)
Stack mutable/immutable val st=scala.collection.mutable.Stack(1,2,3) //堆栈,先进后出
Queue mutable/immutable val q=scala.collection.mutable.Queue(1,2,3) //队列,先进先出
BitSet mutable/immutable val bit=scala.collection.mutable.BitSet(3,2,0) //位集合
ListMap immutable val map = scala.collection.immutable.ListMap(1->"one", 2->"two")
HashSet mutable val set= scala.collection.mutable.HashSet(1,2,3)
HashMap mutable val stu= scala.collection.mutable.HashMap("name" -> "Jason", "age" -> "18")

9、集合常用操作

1)List常用操作

  • 追加操作(新对象)

    • 用于不可变对象,会生成新对象:
    • +: 新加变量为主,在新变量后追加整个集合
    • :+ 集合为主,在集合的后面追加新变量
  • 扩充操作(本对象)

    • 用于可变对象,直接修改本list:
    • += 集合为主,在集合后面追加新变量
    • +=: 新加变量为主,在集合的前面追加新变量
    • ++=: 新加变量为主且该变量为List类型,在集合的前面追加新变量
  • 分组操作

    • grouped n(等价于list.grouped(n)),n个为一组
    • sliding(n,step),每次显示n个,,起始位置s是0。滚动显示,默认步长step为1

2)Set常用操作

  • SortSet ,可以排序的set

  • Set,去重的

  • 增删操作

    • += 修改自身,追加一个内容
    • -= 修改自身,删除一个内容
    • -- 删除一系列内容
    • ++ 增加一系列内容
  • 逻辑运算

    • | 求并集intersect
    • & 求交集union
    • &~ 求差集diff

3)Map常用操作

4)Stream&Vector

  • Stream是惰性List,参数值只会在使用到的时候才会初始化
  • Vector是连续存储的List,访问效率比随机存储的list更高

10、空值

  1. Nil 继承了List[Nothing类],指空List
  2. None 继承了Option[Nothing] 类,指的是Option的空值
  3. Null是指空引用类型,null是引用的空值
  4. Nothing 是Any的子类的,代表类型的的空(指没有类型,Null空类型也是一种类型),类型为空的变量必须是空的,没有实例

函数

一切函数都是值,一切值都是对象,一切对象都可以是函数

def 函数名([参数列表]):[返回值类型]={
    print("我是个函数")
    return [表达式]  
    //return 是可选的,如果不定义,自动返回最后一个行的值
}

1)函数调用

  • 传值参数

    //假设调用时为square(1+2)
    def square(x:Int):Int={
        print(x) //3
        x*x //3*3
    }
    
  • 传名调用,x不计算,仅传递代码体

    • 与闭包搭配,外面修改x后,函数每次都会重新计算参数值因此会实时更新X
    def square(x: => Int):Int={  //注意空格
        print(x) //1+2,在print中计算
        x*x //(1+2)*(1+2)
    }
    

!!!一切皆地址,函数也是地址,函数名只是引用的函数地址!!!

2)函数参数/函数返回值

语法结构:

def 函数名(形参名:(形参函数参数类型表)=> 形参函数返回值类型):[返回值]={
	//调用形参函数
    形参函数名(参数)
}

demo实例

def myfun(fun:Int => Unit):Unit={
    fun(1)//注意,这里的fun是形参函数名
}
def fun(x:Int):Unit={
    print(x)
}
myfun(fun(1))
//:Unit 可以省略 ,默认就是无返回值

//参数为空
def NullPara(){}
或者
def NullPara(null: =>String):String{}//省略了类型

//常用高阶函数
val l=List(1, 2, 3, 4, 5, 6, 7, 8, 9)
l.map(_*2).foreach(println)
l.map(_*2).filter(_>8).foreach(println)l.fold(0)((sum,i)=>sum+i)
l.take(4).foreach(println)//非高阶
println(l.reduce(_+_))
println(l.reduce(_-_))
println(l.max)
println(l.count(_>3))
println(l.min)
println(l.sum)

val a=List(1,2,3,4)
val b=List("A","B","C","D")
println(a zip b)
val c=List("A","B","C","D","E")
println(a zip c)
val d=List(1,2,3,4,5)
println(d zip c)
List("zhangsan","lisi","wangwu").zip(List(100,90,75,83))

val f=List(List(1,2),List(3,4),List(5,6))
println(f.flatten)
println(f.flatMap(_.map(_*2)))

3)匿名函数

  • 关键字符:=>
  • 左边为(函数参数),右边为{ 函数体 }
(x:Int)=>{print(x)}
//因为匿名,没有引用变量,没法直接使用,要么赋值给变量,要么作为实参

myfun((x:Int)=>{print(x);print(x+x)})
//一般使用在函数参数处
//多条语句使用分号隔开
  • scala内置的大部分接口函数都支持匿名函数,可以自定义匿名函数作为foreach和map函数的参数

4)函数变量& def关键字

a)函数变量

//函数有参时
var funVar=myfun _  //相当于引用了函数地址
var funvalue=myfun  //报错
def funbody=myfun _	//相当于重名名函数
//使用下划线缺省函数参数
//可以说val其实是拿到了函数de返回值

//函数无参时
var funvar=myfun  //无参myfun等价于myfun(),执行函数并返回值给funvar

funVar("xixi")
  • var或者val定义的函数变量:定义时执行一次函数体,之后每次调用只能得到函数体的返回值return值
  • def定义的函数变量:定义时不执行函数体,之后每次调用都会完整的运行一遍函数体

b)def关键字

  • def不仅仅用于定义函数和函数变量

5)嵌套函数

  • 函数中可以再次定义函数,这个子函数只有在本函数内可见。

    def factorial(i: Int): Int = {
          def fact(i: Int, accumulator: Int): Int = {
             if (i <= 1)
                accumulator
             else
                fact(i - 1, i * accumulator)
          }
          fact(i, 1)	//不能在factorial()之外调用
       }
    

6)cury柯里化

demo实例

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

柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

  • 子函数依次产生,每个子函数根据当前参数返回新的子函数。
  • 参数1--->子函数1(参数2)--->子函数2(参数3) >>>>>最终返回函数的最终返回值
  • 更加灵活的调用同一个函数

灵活运用demo

def sum(x:Int)(y:Int)={
    print(x+y)
}
def f1(x:Int)=sum(1)(x)
def f2(y:Int)=sum(x)(2)
def f3(z:Int)=sum(3)_
def f4(g:Int)=sum_(4)
def f5(()()=>)

7)隐式函数/隐式参数

demo参数

implict var today="2018-10-25"
def mkLog(arg:String,implict date:String){
 	print(date+" "+arg)
}
mkLog("Success") //运行成功,作用域内找到合适类型的参数,使用隐式参数
mkLog("Success","2018-1-1") //运行成功

demo 函数

"100"/10   //ERROR 类型错误
def String2Int(str:String)={
    str.toInt
}
"100"/10  //类型错误-->发现合适的类型转换函数-->调用-->隐式转换
res1:10
  • 隐式转换和调用只会发生在发生类型错误的时候
  • 两者都需要有implict声明
  • 只能发生在当前作用域内进行值和函数的查找

8)命名参数&参数缺省值

  • 命名参数:即在调用函数的时候声明值的形参名

    def function(str1:String,str2:String){
        print(str1+str2)
    }
    function(str2="xixi",str1="haha");
    //res1:hahaxixi
    
  • 参数缺省值:即在定义函数的时候给出参数的default值

    def sum(a:Int=1,b:Int=2){
    print(a+b)
    }
    sum()
    //res1:3
    //与命名参数一起使用更佳
    sum(b=10)
    //res2:11
    sum(10)
    //res3:12
    

常用高阶函数

  • 高阶函数,以函数作为参数

————————————————————————————————

1、map

  • 集合的函数映射,生成新的集合

2、foreach

  • 相当于for循环内部函数体

3、filter

  • 自定义函数过滤器
lst.filter((x:Int)=>x>50)
lst.filter(_>50)
//参数函数返回值为true的元素才会被保留

4、reduce

lst.reduce(_+_)
lst.reduce((x:Int,y:Int)=>{x+y})

5、fold

lst.fold(5)(_+_)
//与reduce相似,但有一个预先值作为第一个值

//foldRight 从右侧开始

6、zip

//类似于拉链,逐个嵌套
var lst2=lst.map(_*2)
lst1.zip(lst2)
//生成了键值对列表
//长度以最短的list为准

7、flatten

//将复杂类型的内部嵌套展开
//只保留最外层的复杂类型结构
var map1=lst.map(x=>List(x))
map1.flatten
map1.flatten(_.map(_*2))

8、flatMap

//先对子复杂结构进行map
//然后flatten各子元素map的结果
map1.flatMap(_.map(_*2))
原文地址:https://www.cnblogs.com/whoyoung/p/11424428.html