1447

SCALA基础

SCALA基础

<ul><li>

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

<h3>!!!!一切值都是对象,一切函数都是值!!!!</h3> </li> <li>

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

</li> <li>

数学式的语法思维

</li> </ul>

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

IDEA开发环境准备:

1、安装JDK、SCALA环境

2、IDEA安装scala插件

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

4、创建文件,后缀为scala

5、scala可以直接与java交互

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

[TOC]

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

<h3>1、标识符</h3> <ul><li>字母数字标识符:使用字母或者下划线开头,$符号在SCALA中也被看做是字母,但应该尽量避免定义$开头的变量,因为SCALA存在保留变量以$开头</li> <li>符号:符号标识符包含一个或多个表示符,SCALA编译时会将符号转换为$开头的变量名,如:->会被转义为$column$minus$greater,可以看出会转义为$英文单词,因此在java中调用scala程序时要使用转义后的符号</li> </ul><h3>2、import导包</h3> <ul><li>SCALA的import可以出现在任何地方,有效范围:从声明处开始到程序最后结束。</li> <li>SCALA会默认导入java.lang._ ,scala._包,因此以scala开头的包使用时会省略包名的引用。</li> </ul><h3>3、变量与常量</h3> <ul><li>

vaR定义变量

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

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

</li> <li>

vaL定义常量

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

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

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

<h3>4、变量类型结构</h3> <ul><li>

Any 顶级类型

<ul><li>

AnyVal

<ul><li>Unit</li> <li>Byte、Short、Int、Long、Float、Double、Char、Boolean</li> <li>空值:Nothing</li> </ul></li> <li>

AnyRef(java.lang.Object)

<ul><li>List</li> <li>Option</li> <li>MyClass</li> <li>空值:Null</li> </ul></li> </ul></li> </ul><h3>5、类型别名</h3> <ul><li>type关键字,type 别名=类型 ,类似C语言中的typedef typedef sturct{}mystruct stu</li> </ul>

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

<h1 data-breakpage="">流程语句语法

<h4>1、while循环</h4> var i:Int=0; while(i<100){ println(i) i=i+1 } do{ println(i) i=i+1 }while(i<200) <h3>2、for循环</h3> 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 创建的区间是相同的 <h3>3、中断break和breakable</h3> <ul><li>关于Break和Continue,要导入包才可以使用</li> </ul>impot import scala.util.control.Breaks.break impot import scala.util.control.Breaks.breakable <ul><li>breakable(语句块),内部嵌套break即可跳出本次循环</li> <li>卸载breakable外面的break直接跳出循环</li> <li>breakable即可打断的语句块,相当于在循环中又嵌套了一层可被打断的语句块,将代码写在其中即可实现continue</li> </ul><h3>4、多条件循环</h3> <ul><li>多重循环条件+分号;</li> </ul>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也是个函数 <h3>5、数组</h3>

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

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

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

ArrayBuffer 可变长数组

<ul><li>万物皆函数,因此数组也是使用的小括号()</li> <li>定长数组</li> </ul>//方式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 <ul><li>变长数组</li> </ul>import scala.collection.mutable.ArrayBuffer var arrbuf:ArrayBuffer[String]=new ArrayBuffer[String] <h3>6、元组</h3> <ul><li>Tuple可以包含不同类型的值,类型以实际存储的元素类型为准</li> <li>元组最多支持22个元素</li> <li>使用name._1访问name元组的第1个元素,元祖没有0号位</li> <li>元组的类型:元组的实际类型取决于它的分量的类型,比如的(2,"string")类型实际为 Tuple2[Int,String],而 (‘u’,’r’,”the”,1,4,”me”) 的类型为 Tuple6[Char,Char,String,Int,Int,String]</li> </ul>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 //有点类似于样例类

<h3>7、集合Collection</h3>

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

2、集合Set

3、映射Map

<h3>8、mutable和immutable不可变集合</h3>

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

<ul><li>

包名:scala.collection.mutable|immutable.

</li> <li>

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

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

1)List常用操作

<ul><li>

追加操作(新对象)

<ul><li>用于不可变对象,会生成新对象:</li> <li>+: 新加变量为主,在新变量后追加整个集合</li> <li>:+ 集合为主,在集合的后面追加新变量</li> </ul></li> <li>

扩充操作(本对象)

<ul><li>用于可变对象,直接修改本list:</li> <li>+= 集合为主,在集合后面追加新变量</li> <li>+=: 新加变量为主,在集合的前面追加新变量</li> <li>++=: 新加变量为主且该变量为List类型,在集合的前面追加新变量</li> </ul></li> <li>

分组操作

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

2)Set常用操作

<ul><li>

SortSet ,可以排序的set

</li> <li>

Set,去重的

</li> <li>

增删操作

<ul><li>+= 修改自身,追加一个内容</li> <li>-= 修改自身,删除一个内容</li> <li>-- 删除一系列内容</li> <li>++ 增加一系列内容</li> </ul></li> <li>

逻辑运算

<ul><li>| 求并集intersect</li> <li>& 求交集union</li> <li>&~ 求差集diff</li> </ul></li> </ul>

3)Map常用操作

4)Stream&Vector

<ul><li>Stream是惰性List,参数值只会在使用到的时候才会初始化</li> <li>Vector是连续存储的List,访问效率比随机存储的list更高</li> </ul> <h3>10、空值</h3> <ol><li>Nil 继承了List[Nothing类],指空List</li> <li>None 继承了Option[Nothing] 类,指的是Option的空值</li> <li>Null是指空引用类型,null是引用的空值</li> <li>Nothing 是Any的子类的,代表类型的的空(指没有类型,Null空类型也是一种类型),类型为空的变量必须是空的,没有实例</li> </ol> <h1 data-breakpage="">函数

<h3>一切函数都是值,一切值都是对象,一切对象都可以是函数</h3> def 函数名([参数列表]):[返回值类型]={ print("我是个函数") return [表达式] //return 是可选的,如果不定义,自动返回最后一个行的值 } <h3>1)函数调用</h3> <ul><li>

传值参数

//假设调用时为square(1+2) def square(x:Int):Int={ print(x) //3 x*x //3*3 } </li> <li>

传名调用,x不计算,仅传递代码体

<ul><li>与闭包搭配,外面修改x后,函数每次都会重新计算参数值因此会实时更新X</li> </ul>def square(x: => Int):Int={ //注意空格 print(x) //1+2,在print中计算 x*x //(1+2)*(1+2) } </li> </ul><h3>!!!一切皆地址,函数也是地址,函数名只是引用的函数地址!!!</h3> <h3>2)函数参数/函数返回值</h3>

语法结构:

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))) <h3>3)匿名函数</h3> <ul><li>关键字符:=></li> <li>左边为(函数参数),右边为{ 函数体 }</li> </ul>(x:Int)=>{print(x)} //因为匿名,没有引用变量,没法直接使用,要么赋值给变量,要么作为实参 myfun((x:Int)=>{print(x);print(x+x)}) //一般使用在函数参数处 //多条语句使用分号隔开 <ul><li>scala内置的大部分接口函数都支持匿名函数,可以自定义匿名函数作为foreach和map函数的参数</li> </ul><h3>4)函数变量& def关键字</h3>

a)函数变量

//函数有参时 var funVar=myfun _ //相当于引用了函数地址 var funvalue=myfun //报错 def funbody=myfun _ //相当于重名名函数 //使用下划线缺省函数参数 //可以说val其实是拿到了函数de返回值 //函数无参时 var funvar=myfun //无参myfun等价于myfun(),执行函数并返回值给funvar funVar("xixi") <ul><li>var或者val定义的函数变量:定义时执行一次函数体,之后每次调用只能得到函数体的返回值return值</li> <li>def定义的函数变量:定义时不执行函数体,之后每次调用都会完整的运行一遍函数体。</li> </ul>

b)def关键字

<ul><li>def不仅仅用于定义函数和函数变量</li> </ul><h3>5)嵌套函数</h3> <ul><li>

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

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()之外调用 } </li> </ul><h3>6)cury柯里化</h3>

demo实例

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

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

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

灵活运用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(()()=>) <h3>7)隐式函数/隐式参数</h3>

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 <ul><li>隐式转换和调用只会发生在发生类型错误的时候</li> <li>两者都需要有implict声明</li> <li>只能发生在当前作用域内进行值和函数的查找</li> </ul><h3>8)命名参数&参数缺省值</h3> <ul><li>

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

def function(str1:String,str2:String){ print(str1+str2) } function(str2="xixi",str1="haha"); //res1:hahaxixi </li> <li>

参数缺省值:即在定义函数的时候给出参数的default值

def sum(a:Int=1,b:Int=2){ print(a+b) } sum() //res1:3 //与命名参数一起使用更佳 sum(b=10) //res2:11 sum(10) //res3:12 </li> </ul><h3>常用高阶函数</h3> <ul><li>高阶函数,以函数作为参数</li> </ul>

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

1、map

<ul><li>集合的函数映射,生成新的集合</li> </ul>

2、foreach

<ul><li>相当于for循环内部函数体</li> </ul>

3、filter

<ul><li>自定义函数过滤器</li> </ul>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))

来源:博客园

作者:WhoYoung

链接:https://www.cnblogs.com/whoyoung/p/11424428.html

Recommend