首页 技术 正文
技术 2022年11月20日
0 收藏 321 点赞 3,789 浏览 9268 个字

scala

1.   scala的由来

scala是一门多范式的编程语言,一种类似java的编程语言[2] ,设计初衷是要集成面向对象编程和函数式编程的各种特性。

java和c++的进化速度已经大不如从前,那么乐于使用更现代的语言特性的程序员们正在将眼光移向他处。scala是一个很有吸引力的选择;事实上,在我看来,对于想要突破和超越java或者c++的程序员而言,scala是最具吸引力的一个。scala的语法十分简洁,相比java的样板代码,scala让人耳目一新。scala运行于java虚拟机之上,让我们可以使用现成的海量类库和工具。他在拥抱函数式编程的同时,并没有非其面向对象,使你得以逐步了解和学习一种全新的编程范式。scala解释器可以让你快速运行试验代码,这使得学习scala的过程颇为轻松惬意。最后,同时也是很重要的一点,scala是静态类型的,编译器能够帮助我们找到大部分错误,避免时间的浪费。

2.   scala基础

2.1.  scala环境变量安装

见安装文档

2.2.  认识scala

打开cmd,输入scala

2.3.  安装scala-eclipse

2.3.1.   安装

将scala-SDK-3.0.1-vfinal-2.10-win32.win32.x86_64.zip解压到任意目录即可

2.3.2.   打开

2.3.3.   创建scala工程

点击finish

2.3.4.   创建scala包

2.3.5.   创建scala类

2.4.  创建变量

Scala 定义了两种类型的变量 val 和 var ,val 类似于Java中的final 变量,一旦初始化之后,不可以重新赋值(我们可以称它为常变量)。而var 类似于一般的非final变量。可以任意重新赋值。

2.4.1.   不指定类型

package org.apache.first

object test {

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

valmyint = 1

valmystring =”string”

varmyint2 = 1

varmystring2 =”string”

println(myint)

println(mystring)

println(myint2)

println(mystring2)

}

}

你可能注意到了,在变量声明和赋值语句之后,我们并没有使用分号。在scala中,仅当同一行代码中存在多条语句时采用分号隔开,但是其余情况你也可以像java那样使用分号,也不会报错。

2.4.2.   指定类型

当然如果你愿意,你也可以采用和Java一样的方法,明确指定变量的类型,如

valmyint:Int = 1;

valmystring:String =null;

2.4.3.   常用变量

和java一样,scala也有7中数据类型:Byte,Char,Short,Int,Long,Float和Double,以及一个Boolean类型。跟java不同的是,这些类型是类。scala不刻意区分基本数据类型和引用数据类型。你可以对数字执行方法,例如:

1.toString(); //产生字符串“1”

或者,更有意思的是,你可以:

1.to(10)    //产生Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),类似数组

并通过1.to(10)(5)获取其中的值

2.5.  算数和操作符重载

在scala中,+-*%等操作符完成的是和java一样的工作,位操作符&|^>><<也是一样。只有一点特殊的区别:这些操作符实际上是方法。例如:

a+b

是如下调用的简写:

a.+(b)

这里的+就是方法名。

和java和c++相比,scala有一个显著的不同,scala并没有提供++和—的操作。

2.6.  定义函数

Scala既是面向对象的编程语言,也是面向函数的编程语言,因此函数在Scala语言中的地位和类是同等第一位的。下面的代码定义了一个简单的无返回值和有返回值的代码:

2.6.1.   空参无返回值

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

option()

}

def option(): Unit = {

println(“ok”)

}

option函数的返回值类型为Unit 表示该函数不返回任何有意义的值,Unit类似于Java中的void类型

2.6.2.   空参有返回值

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

valreturnval = option()

println(returnval);

}

defoption(): Int = {

}

2.6.3.   有参数有返回值

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

valreturnval = option(3,5)

println(returnval);

}

def option(x:Int,y:Int): Int = {

if (x >y) x

else

y

}

Scala函数以def定义,然后是函数的名称(如option),然后是以逗号分隔的参数。Scala中变量类型是放在参数和变量的后面,以“:”隔开。同样如果函数需要返回值,它的类型也是定义在参数的后面(实际上每个Scala函数都有返回值,只是有些返回值类型为Unit,类似为void类型)。

此外每个Scala表达式都有返回结果(这一点和Java,C#等语言不同),比如Scala的 if else 语句也是有返回值的,因此函数返回结果无需使用return语句。实际上在Scala代码应当尽量避免使用return语句。函数的最后一个表达式的值就可以作为函数的结果作为返回值。

同样由于Scala的”type inference”特点,本例其实无需指定返回值的类型。对于大多数函数Scala都可以推测出函数返回值的类型,但目前来说回溯函数(函数调用自身)还是需要指明返回结果类型的。

3.   控制结构和函数

3.1.  条件表达式if else

scala的if/else语法结构和java一样。不过,在scala中if/else表达式有值,这个值就跟在if或者else之后的表达式值。例如:

if(x>0) 1 else -1

上述表达式的值是1或者-1.

也可以将表达式的值赋予其他变量

val s = if (x>0) 1 else -1

这个语句的写法也可以为:

val x = 0

var s =0

if (x>0) {

s=1

}else{

s=2

}

3.2.  语句终止

在java中,每个语句都以分号结束。而在scala中,与js脚本语言类似,行尾不需要分号。同样,在}和else以及类似的位置也不需要写分号,但是如果你倾向与使用分号,用就是了,他没啥坏处。

3.3.  块表达式和赋值

在java中,块语句使用一个包在{}中的语句序列。每当你需要在逻辑分支或者循环中放置多个动作时,你可以使用块语句。

在scala中,{}块包含一系列表达式,其结果也是一个表达式。块中最后一个表达式的值就是块的值。

例如:

package org.apache.first

import scala.math._

object test {

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

val test = {

val dx = 0;

val dy = 10;

min(dx,dy);

}

println(test)

}

3.4.  循环

3.4.1.   while循环

object test {

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

varn = 10;

while(n>0){

println(n)

n-=1;

}

}

3.4.2.   for

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

for(i <- 1 to 10){

println(i)

}

}

注:1 to 10,返回数字1到数字10,含头含尾。

退出循环

import scala.util.control.Breaks._

object test {

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

for(i <- 1 to 10){

if(i==3) return;

println(i)

}

}

在这里,控制权的转移是通过抛出和捕获异常完成的,因此,如果时间很重要的话,尽量避免使用。

3.4.3.   高级for循环

object test {

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

for(i <- 1 to 10;j <- 1 to 3){

println(i+j)

}

}

objecttest {

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

for(i <- 1 to 10;j <- 1 to 3ifi == j){

println(i+j)

}

}

3.5.  函数

3.5.1.   默认参数

object test {

defmain(args: Array[String]): Unit = {

valaa = option(2);

println(aa);

}

def option(x:Int,y:Int=1): Int = {

if (x >y) x

else

y

}

}

option函数有两个参数,但是y这个参数是带默认值的,所以,如果你只传一个参数x,那么y就会走默认值。

3.5.2.   变长参数

objecttest {

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

option(2,3,4,5,6);

}

def option(args:Int*): Unit = {

println(args(3))

for(arg <- args){

println(arg);

}

}

}

3.5.3.   递归

object test {

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

varaa = option(2,3,4,5,6);

println(aa)

}

def option(args:Int*): Int = {

if(args.length==0){

0

}else{

args.head + option(args.tail: _*)

}

}

}

在这里,args.head是args的首个元素,而tail是所有其他的参数序列,_*是将args.tail转换成一个序列。类似于js的eval()。

3.6.  过程

scala对于不返回值的函数有特殊的表示法。如果函数体包含在花括号当中,但是没有等号“=”,那么返回值类型就是Uint。这样的函数被称为过程(procedure)。过程不返回任何值。

object test {

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

option(2);

}

def option(x:Int) = {

println(x+5)

}

}

也可以声明Unit返回值。

3.7.  懒值

当val被声明为lazy时,它的初始化将被推迟,知道我们首次对它取值。例如:

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

lazyvalwords = scala.io.Source.fromFile(“/usr/local/a.txt”).mkString;

//println(words);

}

如果不访问words,那么文件不会被打开,但是去掉lazy或者访问words的时候,就会报错。

3.8.  异常

scala的异常工作机制和java的一样。当你抛出异常时,比如:

throw new IllegalArgumentException(“aaa”);

当前的运算被中止。不过与java不同的是,scala不需要声明函数会抛出哪种异常。

try{

}catch{

}finally{

}

4.   数组及操作

4.1.  定长数组

//3个整数的数据,所有元素为0

val arr1 = new Array[Int](3)

val arr2 = Array(0, 0, 0)

val arr3 = Array(“hadoop”, “spark”)

//取值、赋值

val str = arr3(1)

arr3(1) = “storm”

4.2.  变长数组

ArrayBuffer类似Java中的ArrayList

val a = ArrayBuffer[Int]()

或val a = new ArrayBuffer[Int]

a +=1 //在尾端添加元素

a +=(1,2,3) //追加多个元素

a ++= ArrayBuffer(7,8,9) //追加集合

a.trimEnd(2)  //移除最好两个元素

a.insert(2, 6, 7)  //在下标2之前插入6,7

a.remove(2, 2)  //从下标2开始移除2个元素

val b = a.toArray  //转变成定长数据组

b.toBuffer  //转变成变长数据组

4.3.  遍历数组

val arr = Array(1,2,3,4,5)

//带下标的for循环

for (i <- (0 until (arr.length, 2)).reverse) {        println(arr(i))

}

//增强for循环

for (i <- arr) println(i)

4.4.  数组转换

转换动作不会修改原始数组,而是产生一个全新的数组

val arr = Array(1,2,3,4,5,6,7,8,9,10)

for(e <- arr) yield e //生成一个与arr一样的

for(e <- arr if e % 2 == 0) yield e * 2

//思考:如何变得跟简单

4.5.  数组的常用算法

val arr = Array(4,3,5,1,2)

val res = arr.sum

Array(“spark”,”hadoop”, “storm”).min

val b = arr.sorted

val c = arr.sortWith(_>_)

val d = arr.count(_>2)

5.   映射

val map = Map(“a”->1, “b”->2, “c”->3)

或 val map = Map((“a”,1), (“b”,2), (“c”,3))

//取值、赋值

map(“a”)

map.getOrElse(“d”, 0)

map(“b”) = 22

map += (“e”->8, “f”->9)

map -= (“f”)

//迭代

for((k,v) <- map)

//交换k,v

for((k,v) <- map) yield (v,k)

//keySet和values

6.   元祖

元组是不同类型元素的集合

val t = (“hadoop”, 1000, “spark”)

val a = t._3 //元组中的下标是从1开始

“NewYork”.partition(_.isUpper)

7.   复杂的集合操作方法

7.1.1.   map

讲数组中的值取出来

val a = Array(6,7,8,9)

计算:

a.map(_*2)// Array[Int] = Array(12, 14, 16, 18)

数组转成Array(tuple):

map((_,1))// Array((6,1), (7,1), (8,1), (9,1))

val map = Map(“a”->1, “b”->2, “c”->3)

map.map(x=>x._1)//取出map的第一个值

map.map(x=>(x._1,x._2))//取出map的所有值

7.1.2.   flatten

把数组压平

语法:

val a = Array(Array(6,7,8,9), Array(10,11,12,13,14))

val res = a.faltten// val a = Array(Array(6,7,8,9), Array(10,11,12,13,14))

7.1.3.   groupby

分组

val map = Map(“a”->1, “b”->2, “c”->3)

按照key分组:map.groupBy(_._1)

结果:Map(b -> Map(b -> 2), a -> Map(a -> 1), c -> Map(c -> 3))

7.1.4.   foldLeft

传入初始值后,多数组元素叠加

val a = Array(1,2,3,4,5)

a.foldLeft(0)(_+_) //15

7.1.5.   reduce

val a = Array(1,2,3,4,5)

a.reduce(_+_) //15

7.1.6.   aggregate

aggregate函数将每个分区里面的元素进行聚合,然后用combine函数将每个分区的结果和初始值(zeroValue)进行combine操作。这个函数最终返回的类型不需要和RDD中元素类型一致。

计算两个数组的和

val a = Array(Array(1,2,3),Array(4,2,3))

  1. aggregate(0)(_+_.sum,_+_)

7.1.7.   flatMap

先map后foldLeft

7.1.8.   reduceByKey

7.1.9.   sortByKey

7.1.10.           sortBy

8.   类

8.1.  类的定义和getset方法

带getter和setter属性

var

只带getter属性

val

private和private[this]

8.2.  主构造器和辅助构造器

1、跟在类名后面的是主构造器

2、辅助构造器的名称为this定义,必须执行def

3、辅助构造函数相当于java中的其他的累的构造器,所接受的参数不能多于主类的

例如

class TestScala1 (val name: String,var password:String ) {

def this(name: String) = this(name,null)

}

8.3.  object半生对象

用对象作为单例或存放工具方法

可作为伴生对象

用类的伴生对象的apply方法创建新的实例

扩展App特质作为main方法使用

枚举

8.4.  包

包可见性private[spark]

重命名import java.util.{HashMap => JHashMap}

隐式导入:和Java程序一样java.lang总是被默认引入,scala也默认引入

8.5.  模式匹配

Scala有一个非常强大的模式匹配机制,可以应用到很多场合:如switch、类型查询,并可以结合样例类完成高级功能

object TestScala1 {

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

val aa = new TestScala2

println(aa.test(“zhangsan”))

}

}

class TestScala2 {

def test(name: String): String = {

//和java的switch一样,只是关键字变成了match,分在=》后面的是一个方法体,而=》符号表示匿名函数

name match {

case “zhangsan” => TestScala2.test(name)

case “lisi” => name+”fdsfas”

case _ => name+”fdsfas”

}

}

}

object TestScala2 {

def test(name: String): String = {

“wangwu”

}

}

8.6.  样本类

caseclass TestScala1(valname: String, varpassword: String) {

defthis(name: String) = this(name, null)

defthis() = this(nullnull)

}

 样本类:添加了case的类便是样本类。这种修饰符可以让Scala编译器自动为这个类添加一些语法上的便捷设定。如下:

添加与类名一致的工厂方法。也就是说,可以写成Var(“x”)来构造Var对象。

样本类参数列表中的所有参数隐式获得了val前缀,因此它被当作字段维护。

编译器为这个类添加了方法toString,hashCode和equals等方法。

9.   继承

重新方法:重新一个非抽象的方法必须使用override修饰符

o.isInstanceOf[Cl] //java中的instanceof

o.asInstacneOf[Cl] //java中的 (Cl) o

classOf[Cl] //java中的Cl.class

10.         高阶函数

def fun(f: Double => Double) = {

f(100)

}

fun((x : Double) => 2 * x)

fun(sqrt _)

11.         柯里化

将原来接受两个参数的函数变成接受一个参数的函数的过程。

例如定义一个函数是这样滴:

def first(x:Int) = (y:Int) => x + y

那么调用的时候应该这样写

val second=first(1)

val result=second(2)

实际上柯里化函数将上面的步骤简化了:

简化成这样定义:

def fun(x: Int)(y: Int) = x * y

调用时你可以这样:

fun(6)(7)

也可以这样:

val fun2 = fun(6)_   // 这次调用返回的是一个方法,传入一个值,但是本身这个函数需要两个值,所以我们用”_”来站位我们不知道的另一个参数

val result = fun2(7)   // 42

12.         隐式转换

隐式转换:就是将某各类中没有的方法实现,在另一个增强类中实现,然后用一个固定的方式将某各类转换成这个增强类

  1. 例如:java的file类中并没有read方法,那么我们想读文件,需要利用scala的source这个类帮我们读文件
  2. 那么,我们重新定义一个类RichFile,接受的参数是File类型,而利用Source.fromFile(file.getPath()).mkString帮助我们读取文件,但是这个方法位于RichFile中,无法让File类直接使用,所以我们需要将File转换成RichFile
  3. 那么,我们写一个object伴生对象,将我们的File转换成RichFile,书写如下,注意必须有impilicit关键字声明方法:implicit def file2RichFile(f:File)= new RichFile(f)
  4. 在我们需要使用File调用read方法时,import之前的半生对象即可import Context._

package org.apache.scala.one

import scala.collection.mutable.Map

import scala.math._

import scala.io.Source

import java.io.File

class RichFile(val file:File){

def read = Source.fromFile(file.getPath()).mkString

}

object Context{

implicit def file2RichFile(f:File)= new RichFile(f)

}

object ImplicitDemo extends App{

import Context._

println(new File(“c:/sss.txt”).read)

1.to(10)

}

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,893
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,422
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,240
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,054
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,683
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,720