Scala学习之路----基础入门

一、Scala解释器的使用

REPL:Read(取值)-> Evaluation(求值)-> Print(打印)-> Loop(循环)

scala解释器也被称为REPL,会快速编译scala代码为字节码,然后交给JVM来执行。

计算表达式:在scala>命令行内,键入scala代码,解释器会直接返回结果。

如果你没有指定变量来存放这个值,那么值默认的名称为res,而且会

显示结果的数据类型,比如Int、Double、String等等。

例如,输入1 + 1,会看到res0: Int = 2

内置变量:在后面可以继续使用res这个变量,以及它存放的值。

例如,"Hi, " + res0,返回res2: String = Hi, 2

自动补全:在scala>命令行内,可以使用Tab键进行自动补全。

二、声明变量

声明val常量:可以声明val常量来存放表达式的计算结果。

例如,val result = 1 + 1

但是常量声明后,是无法改变它的值的,否则会返回error: reassignment

to val的错误信息。

声明var变量:如果要声明值可以改变的引用,可以使用var变量。

例如,var myresult = 1,myresult = 2

但是在Scala程序中,通常建议使用val,也就是常量。

因为在Spark的大型复杂系统中,需要大量的网络传输数据,

如果使用var,值可能被错误的更改,所以建议多使用val。

三、数据类型与操作符

1》基本数据类型: Byte、 Char、 Short、 Int、 Long、 Float、 Double、 Boolean。

Scala的数据类型统一都是类。 Scala自己会负责基本数据类型和引用类型的转换操作。

使用以上类型, 直接就可以调用大量的函数, 例如, 1.toString(), 1.to(10)。

类型的加强版类型: Scala使用很多加强类给数据类型增加了上百种增强的功能或函数。

·例如, String类通过StringOps类增强了大量的函数, "Hello".intersect(" World")。

·例如, Scala还提供了RichInt、 RichDouble、 RichChar等类型, RichInt就提供了to函数, 1.to(10), 此处Int先隐式转换为RichInt,然后再调用其to函数。

2》基本操作符: Scala的算术操作符与Java的算术操作符也没有什么区别, 比如+、 -、 *、 /、 %等, 以及&、 |、 ^、 >>、 <<等。

但是, 在Scala中, 这些操作符其实是数据类型的函数, 比如1 + 1, 可以写做1.+(1)

例如, 1.to(10), 又可以写做1 to 10

注:Scala中没有提供++、--操作符, 我们只能使用+和-, 比如counter = 1,counter++是错误的, 必须写做counter += 1

3》除了方法之外,Scala还提供函数

数学函数:sqrt() pow() min()

引入特定包时使用import 包名._;

import scala.math._ ,_是通配符,类似Java中的*

四、流程控制结构

1、if表达式的定义: 在Scala中, if表达式是有值的, 就是if或者else中最后一行语句返回的值。

例如, val age = 30; if (age > 18) 1 else 0

可以将if表达式赋予一个变量, 例如, val isAdult = if (age > 18) 1 else 0

另外一种写法, var isAdult = -1; if(age > 18) isAdult = 1 else isAdult = 0, 但是通常使用上一种写法

2、if表达式的类型推断: 由于if表达式是有值的, 而if和else子句的值类型可能不同, 此时if表达式的值是什么类型呢?

Scala会自动进行推断, 取两个类型的公共父类型Any。

例如, if(age > 18) 1 else 0, 表达式的类型是Int, 因为1和0都是Int

例如, if(age > 18) "adult" else 0, 此时if和else的值分别是String和Int, 则表达式的值是Any, Any是String和Int的公共父类型。

如果if后面没有跟else, 则默认else的值是Unit, 也用()表示, 类似于Java中的void或者null。

例如, val age = 12; if(age > 18) "adult"。 此时就相当于if(age > 18) "adult" else ()。

3、将if语句放在多行中: 默认情况下, REPL只能解释一行语句, 但是if表达式通常需要放在多行。

可以使用{}的方式, 比如以下方式, 或者使用:paste和ctrl+D的方式。

if(age > 18) { "adult"

} else if(age > 12) "teenager" else "children"

注:默认情况下, Scala不需要语句终结符, 默认将每一行作为一个语句

4、一行放多条语句: 如果一行要放多条语句, 则必须使用语句终结符

例如, 使用分号作为语句终结符, var a, b, c = 0; if(a < 10) { b = b + 1;c = c + 1 }

通常来说, 对于多行语句, 还是会使用花括号的方式

var a, b, c = 0;if(a < 10) {

b = b + 1;c = c + 1}

5、块表达式: 块表达式, 指的就是{}中的值, 其中可以包含多条语句, 最后一个语句的值就

是块表达式的返回值。

例如, var d = if(a < 10) { b = b + 1; c + 1 }

6、输入和输出

print和println: print打印时不会加换行符, 而println打印时会加一个换行符。

printf可以用于进行格式化,例如, printf("Hi, my name is %s, I‘m %d years old .", "Leo", 30)

readLine: readLine允许我们从控制台读取用户输入的数据, 类似于Java中的System.in和Scanner的作用。

综合案例:使用paste和ctrl+D

val name = readLine("Welcome to Game House. Please tell me your name: ")

print("Thanks. Then please tell me your age: ")

val age = readInt()

if(age > 18) {

printf("Hi, %s, you are %d years old, so you are legel to come here!", name, age)

} else {

printf("Sorry, boy, %s, you are only %d years old. you are illegal to come here!",

name, age)

}

五、循环

1、Scala拥有与Java相同的while和do-while循环

但没有与for(初始化变量;判断条件;更新变量)循环直接对应的对构。

Scala中的for:for(i<-表达式),让变量i遍历<-右边表达式的所有值。

注意:

1、在for循环的变量之前并没有val或var的指定,该变量的类型是集合的元素类型。

2、循环变量的作用域一直持续到循环结束

3、to 和 until,两者得到都是集合,区别如下:

scala> 1 to 10 (包含10)

res8: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> 1 until 10 (不包含10)

res10: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)

4、循环的几种遍历方式

一、直接遍历------遍历字符串

二、求和---------1到8的和

三、以 变量<-表达式 的形式提供多个生成器,用分号将它们隔开(嵌套循环)

for(i<- 1 to 9;j<- 1 to i){

if(i==j) println(j+"*"+i+"="+j*i)

else print(j+"*"+i+"="+j*i+"\t")

}

四、在循环中使用变量

for(i<- 1 to 6;tem=2*i-1;j<- 1 to tem){

print("*");if(j==tem) {println()}}

五、守卫式,即在for循环中添加过滤条件if语句

for(i<- 1 to 3;j<- 1 to 3 if i!=j) print((10*i+j)+" ")

六、推导式

如果for循环的循环体以yield开始,则该循环会构造出一个集合,每次迭代生成集合中的一个值。

六、函数

1、函数的分类

单行函数:def sayHello(name: String) = print("Hello, " + name)

多行函数:如果函数体中有多行代码, 则可以使用代码块的方式包裹多行代码, 代码块中最后一行

的返回值就是整个函数的返回值。 与Java中不同, 不能使用return返回值。

比如如下的函数, 实现累加的功能:

def sum(n: Int) :Int= {

var sum = 0;

for(i <- 1 to n) sum += i

sum}

2、函数的定义与调用

在Scala中定义函数时, 需要定义函数的函数名、 参数、 函数体。

def sayHello(name: String, age: Int) = {

if (age > 18) { printf("hi %s, you are a big boy\n", name); age }

else { printf("hi %s, you are a little boy\n", name); age}}

调用:sayHello("leo", 30)

注:Scala要求必须给出所有参数的类型, 但是不一定给出函数返回值的类型。

只要右侧的函数体中不包含递归的语句, Scala就可以自己根据右侧的表达式推断出返回类型。

3、递归函数与返回类型

如果在函数体内递归调用函数自身, 则必须给出函数的返回类型。

例如, 实现经典的斐波那契数列:

def feibo(n:Int):Int={

if(n<=2) 1

else feibo(n-1)+feibo(n-2)}

例如如下阶乘:

4、参数

1》默认参数

在Scala中, 有时我们调用某些函数时, 不希望给出参数的具体值, 而希望使用参数自身默认的值, 此时就在定义函数时使用默认参数。

def sayHello(firstName: String, middleName: String = "William", lastName:

String = "Croft") = firstName + " " + middleName + " " + lastName

如果给出的参数不够, 则会从左往右依次应用参数。

Java与Scala实现默认参数的区别如下:

-----------------------------------------------------------------------------------

Java:

public void sayHello(String name, int age) {

if(name == null) {

name = "defaultName"

} if(age == 0) {

age = 18

}}

sayHello(null, 0)

-----------------------------------------------------------------------------------

Scala:

def sayHello(name: String, age: Int = 20) {

print("Hello, " + name + ", your age is " + age)}

sayHello("leo")

2》带名参数

在调用函数时, 也可以不按照函数定义的参数顺序来传递参数, 而是使用带名参数的方式来

传递。如:sayHello(firstName = "Mick", lastName = "Nina", middleName = "Jack")

还可以混合使用未命名参数和带名参数, 但是未命名参数必须排在带名参数前面。如下:

正确:sayHello("Mick", lastName = "Nina", middleName = "Jack")

错误:sayHello("Mick", firstName = "Nina", middleName = "Jack")

3》使用序列调用变长参数

在如果要将一个已有的序列直接调用变长参数函数, 是不对的。 比如val s = sum(1 to 5)。

此时需要使用Scala特殊的语法将参数定义为序列, 让Scala解释器能够识别。

这种语法非常有用!Spark的源码中大量地使用。

例如:val s = sum(1 to 5 : _*) 通过:_*转换成参数序列

案例: 使用递归函数实现累加,如下:

def sum2(nums: Int*): Int = {

if (nums.length == 0) 0

else nums.head + sum2(nums.tail: _*)

}

调用:sum2(1,2,3,4,5) 或是 sum2(1 to 5 :_*)

注:1、定义nums为一个变长参数,定义函数时用*,调用函数需要表示一个参数序列时用:_*

2、head 表示集合中的第一个元素,tail 表示集合中除了第一个元素外的其他元素

七、过程

定义:在Scala中, 定义函数时, 如果函数体直接包裹在了花括号里面, 而没有使用=连接,

则函数的返回值类型就是Unit, 这样的函数就被称之为过程。过程通常用于不需要返回值的函数。

过程还有一种写法, 就是将函数的返回值类型定义为Unit。比较如下:

def sayHello(name: String) = "Hello, " + name

def sayHello(name: String) { print("Hello, " + name); "Hello, " + name }

def sayHello(name: String): Unit = "Hello, " + name

八、lazy值

在Scala中, 提供了lazy值的特性, 也就是说, 如果将一个变量声明为lazy, 则只有在第一次使用

该变量时, 变量对应的表达式才会发生计算。这种特性对于特别耗时的计算操作特别有用, 比如打开文件进行IO, 进行网络IO等。

1、import scala.io.Source._

lazy val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString

即使文件不存在, 也不会报错, 只有第一次使用变量时会报错, 证明了表达式计算的lazy特性

val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString 这句会报错

2、val lines=sc.textFile("file:///home/tg/datas/ws")

val rdd1=lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)

val rdd2=rdd1.collect

算子: flatMap() map() reduceByKey()转换类型的算子(transformation)

collect()行动类型的算子(action)

3、val rdd=lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).map(m=>(m._2,m._1))

.sortByKey(true).map(m=>(m._2,m._1)).collect

注:转换类型的算子就是lazy类型,当遇到action行动类型的算子时,才会触发执行。

总结下划线的用法:

1、导包时,导入包中所有内容 import scala.io.Source._

2、将数列(集合)转换成参数序列 val result=sum(1 to 10:_*)

3、表示Spark算子操作的每一个元素 lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)

八、异常

在Scala中, 异常处理和捕获机制与Java是非常相似的。

try {

throw new IllegalArgumentException("x should not be negative")

} catch {

case _:IllegalArgumentException => println("Illegal Argument!")

} finally {

print("release resources!")

}

try {

throw new IOException("user defined exception")

} catch {

case e1:IllegalArgumentException => println("illegal argument")

case e2:IOException => println("io exception")

}

九、数组

若数组长度固定使用Array,若数组长度不固定则使用ArrayBuffer

1、定长数组的两种创建方式

1》val nums=new Array[Int](10); //10个整数的数组 2》val array=Array("hello","jack")

省略关键字new创建数组的方式,实际上调用的是 Array.scala中的apply()方法。源码如下:

def apply[T: ClassTag](xs: T*): Array[T] = {

val array = new Array[T](xs.length)

var i = 0

for (x <- xs.iterator) {

array(i) = x;

i += 1 }

array}

2、变长数组:数组缓冲

注:scala.collection.mutable._ 可变 scala.collection.immutable._ 不可变

对于那种长度按需要变化的数组,Java有ArrayList,Scala有ArrayBuffer

变长数组ArrayBuffer使用时要导包 import scala.collection.mutable.ArrayBuffer

var arr1=ArrayBuffer[Int]()

变长数组操作:1、arr1+=1 2、arr1+=(2,5,6) 3、arr1 ++=Array(3,4)

4、arr1.trimEnd(5) 返回值为空,需再次调用arr1来查看删除后的数据

5、arr1.insert(1,3,4) 指定1的位置添加3,4元素

6、arr1.remove(3)

7、arr1.remove(3,2) 指定位置删除指定数量的元素

3、变长数组与定长数组之间的转换

变长数组→定长数组:.toArray (不改变原来的数组,系统会自动创建一个新的arry)

定长数组→变长数组:.toBuffer

4、遍历数组

until是RichInt类的方法, 返回所有小于( 不包括) 上限的数字。

5、数组常用算法

,除了sum求和,max最大值,min最小值以外还有如下:

6、数组的quickSort()快速排序方法scala.util.Sorting.quickSort(array)

十、高阶函数

filter :把一个函数作为参数的函数

for(i <- 0 until arr1.length if(arr1(i)%2==0)) print(arr1(i)+" ")

array.filter(m=>m%2==0) 这里的m可以省去简写成 array.filter(_%2==0)

m=>m%2==0 匿名函数 m=>{m%2==0}

算子: spark中的算子有一部分是和scala中的高阶函数是一致的,

但是有一部分是scala中没有的,比如reducekey

简写用下划线代替m: val rdd=lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)

lines.flatMap(m=>m.split(" ")).map(word=>(word,1)).reduceByKey((x,y)=>x+y)

十一、映射(Map)

1、Scala映射就是键值对的集合Map。默认情况下,Scala中使用不可变的映射。

如果想使用可变集合Map,必须导入scala.collection.mutable.Map

不可变:

val map=Map("tom"->20,"jack"->23,"marray"->22)

val map2=Map(("tom",20),("jack",23),("marray",22))

可变:

val map3=scala.collection.mutable.Map(("tom",20),("jack",23),("marray",22))

val map4=new scala.collection.mutable.HashMap[String,Int]

映射这种数据结构是一种将键映射到值的函数。 区别在于通常的函数计算值, 而映射只是做查询。

2、获取映射中的值

注:1》如果映射并不包含请求中使用的键, 则会抛出异常。

2》要检查映射中是否有某个指定的键, 可以用contains方法。

3》getOrElse方法, 若包含相应的键, 就返回这个键所对应的值, 否则返加0。

4》映射.get(键)这样的调用返回一个Option对象, 要么是Some(键对应的值), 要么是None。

3、修改Map的元素

更新可变Map集合:

1》更新Map的元素 ages(www.quyingyulecs.com "Leo") = 31

2》增加多个元素 ages += ("Mike" -> 35, "Tom" -> 40)

3》 移除元素 ages -= "Mike"

更新不可变Map集合:

1》 添加不可变Map的元素, 产生一个新的集合Map, 原Map不变

val ages2 = ages + ("Mike" -> 36, "Tom" -> 40)

2》移除不可变Map的元素, 产生一个新的集合Map, 原Map不变

val ages3 = ages - "Tom"

4、遍历Map操作

//遍历map的entrySet for ((key, value) <- ages) println(key + " " + value)

// 遍历map的key for (key <- ages.keySet) println(key)

// 遍历map的value for (value <- ages.values) println(value)

// 生成新map, 反转key和value for ((key, value) <- ages) yield (value, key)

5、SortedMap和LinkedHashMap

// SortedMap可以自动对Map的key的排序

val ages = scala.collection.immutable.SortedMap("leo" -> 30, "alice" -> 15, "jen" -> 25)

// LinkedHashMap可以记住插入entry的顺序

val ages = new scala.collection.www.dasheng178.com/ mutable.LinkedHashMap[String, Int]

ages("leo") = 30

ages("alice") = 15

ages("jen") = 25

6、Java Map与Scala Map的隐式转换

import scala.collection.JavaConversions.mapAsScalaMap

val javaScores = new java.util.HashMap[String, Int]()

javaScores.put("Alice", 10)

javaScores.put("Bob"www.mhylpt.com, 3)

javaScores.put("Cindy", 8)

val scalaScores: scala.collection.mutable.Map[String, Int] = javaScores

===========================================================

import scala.collection.JavaConversions.mapAsJavaMap

import java.awt.font.TextAttribute._

val scalaAttrMap = Map(FAMILY -> "Serif", SIZE -> 12)

val font = new java.awt.Font(scalaAttrMap)

7、元组(tuple)

概念:元组是不同类型的值的聚集,对偶是元组的最简单形态,元组的索引从1开始,而不是0

Tuple拉链操作:

Tuple拉链操作指的就是zip操作,zip操作是Array类的方法, 用于将两个Array, 合并为一个Array

比如 Array(v1)和Array(v2), 使用zip操作合并后的格式为Array((v1,v2)),合并后的Array的元素类型为Tuple。例子如下:

val students = Array("Leo", "Jack", "Jen")

val scores = Array(80, 100, 90)

val studentScores = students.zip(scores)

for ((student, score) <- studentScores) println(student + " " + score)

注:如果Array的元素类型是Tuple, 调用Array的toMap方法, 可以将Array转换为Map

如,studentScores.toMap

原文地址:https://www.cnblogs.com/qwangxiao/p/9333384.html

时间: 2024-12-08 02:51:34

Scala学习之路----基础入门的相关文章

Python学习之路 - 基础入门

本系列文章使用的Python版本为3.6.2 使用开发工具为Pycharm2017 一.Python介绍 Python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承. 最新的TIOBE排行榜,Python赶超PHP占据第五, Python崇尚优美.清晰.简单,是一个优秀并广泛使用的语言. 目前Python主要应用领域: 云计算:云计算最火的语言, 典型应用Open

Linux学习之路-基础入门【1】---20171106

一.计算机基础知识                                                                                      (希望自己能更加喜欢这个系统的学习)   1.计算机系统 2.存储网络分类 DAS--(DirectAttached Storage)直接连接存储 直接存储,存储设备与主机的紧密相连. NAS--(NetworkAttached Storage)网络连接存储 通过局域网在多个文件服务器之间实现了互联,基于文件

Linux学习之路-基础入门 20191104

1.计算机组成 2.开发接口标准 ABI--(Application Binary Interface) ABI描述了应用程序与OS之间的底层接口,允许编译好的目标代码在使用兼容ABI的系统中无需改动就能运行. API--(Application Programming Interface) API定义了源代码和库之间的接口,因此同样的源代码可以在支持这个API的任何系统中编译(AIEEE在操作系统上定义的一系列API标准). 3.Linux运行文件格式 ELF:可运行文件格式(类似于Windo

Scala学习:第一张基础 - 心得

这是一个神奇的语言. 安装环境就够折腾了,居然还挑eclipse,最新的4.4居然不支持,要用4.3.2 第一张都是些简单的概念介绍,但是通过第一张可以看出scala和其他语言的语法上存在较大的区别(当然根据我的知识范围也就是指的c#,Java) 关键点: 1.Scala中,我们不需要包装类型. 读到这里时,我对性能产生了担心,于是赶快查了下对Scala和Java的性能对比.有个比较好的文章.内容不多,字字珠玑. 不要使用for循环 不要使用scala.collection.mutable 不要

Web 前端开发学习之路(入门篇)

字数1374 阅读4622 评论0 喜欢49 以前学习过一段时间的web前端开发,整理了一些我看过的/我认为比较好的学习资料(网站.书籍).不要问我为啥没有进阶版,我只是一条产品汪而已,求轻喷.== 以下引用知乎 @李路 的话. 以我的经验,大部分技术,熟读下列四类书籍即可. 入门,用浅显的语言和方式讲述正确的道理和方法,如head first系列全面,巨细无遗地探讨每个细节,遇到疑难问题时往往可以在这里得到理论解答,如Definitive Guide/Programming xx系列实践,结合

Scala学习笔记--正则表达式基础知识、如何在scala内使用

正则表达式语法:https://msdn.microsoft.com/zh-cn/library/ae5bf541(VS.80).aspx 基础知识:正则表达式30分钟入门教程 http://www.jb51.net/tools/zhengze.html  版本:v2.33 (2013-1-10) 作者:deerchao 转载请注明来源 使用格式:  见java API  http://docs.oracle.com/javase/7/docs/api/ java : java.util.reg

html5该怎么样学习?零基础入门HTML5学习路线

纵观近几年HTML5的发展可以看出,HTML5开发持续上涨,腾讯.微软.谷歌等国际互联网企业都将HTML5的研发与使用放在了重要的地位.目前全球有超过十亿台手机浏览器支持HTML5,而微信小程序的开放,更是引爆了HTML5的开发浪潮.大量的HTML5游戏风靡全球,也充分体现了HTML5良好的发展势头. 有调查数据显示,高达83.27%的用户认为HTML5技术是大势所趋.而随着互联网时代的到来,使得HTML5的发展前景愈发的明朗,同样也增加了诸多企业对于HTML5高端人才的需求量. 目前,已经有越

#Java学习之路——基础阶段(第一篇)

我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言:此随笔主要是Java基础中的基础,相信大家对这方面肯定有着自己的理解和认识,具体详解可以参照万能的baidu,有的我就一笔带过,希望在我的学习之路上能够有大牛进行指导,也有更多的小伙伴共勉. 1.Java语言的概述(了解即可) 什么是Java语言:作为一个初学者来说,对我而言Java就像我们所知道的

#Java学习之路——基础阶段二(第五篇)

我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言:此随笔主要是Java基础中的基础,相信大家对这方面肯定有着自己的理解和认识,具体详解可以参照万能的baidu,有的我就一笔带过,希望在我的学习之路上能够有大牛进行指导,也有更多的小伙伴共勉. 1.异常 异常在我们平时编译的时候会有两种情况,一种是编译报错,一种是运行报错,还有一种较为严重的就是直接e