Scala学习笔记(三):基础知识
有了可运行的环境,就需要写一些简单的语句来认识一下Scala,本文没有写那么详细,只是为了方便查看、唤起回忆
(1)变量的定义方法
Scala有两种变量
var
val
val 类似于 Java 中的 final 变量,一旦初始化之后,不可以重新赋值
注意:在解释器中,可以用一个之前已经使用了的名字定义新的val
Scala 可以使用两种形式的标志符:字符数字和符号
字符数字:使用字母或是下划线开头,后面可以接字母或是数字
符号:包含一个或多个符号,如+,:,? 等
扩展:
如果你是个 Java 程序员,你会发现 Java 支持的基本数据类型,Scala 都有对应的支持,不过 Scala 的数据类型都是对象(比如整数),这些基本类型都可以通过隐式自动转换的形式支持更多的方法。
譬如:如果调用 (-1).abs() ,Scala 发现基本类型 Int 没有提供 abs()方法,但发现系统提供了从 Int 类型转换为 RichInt 的隐式自动转换,而 RichInt 具有 abs 方法,那么 Scala 就自动将 1 转换为 RichInt 类型,然后调用 RichInt 的 abs 方法。
隐式转换是一项compiler功能,在程序编译(compile)的时候由compiler来进行类型转换代码的产生和替代
一个类型T的隐式作用域就是组成这个类型的所有类的伴生对象(companion object)
(2)函数结构
def max(X:Int,Y:Int):Int={
if(X>Y)
X
else
Y
}
既不带参数也不返回有用结果的函数定义:
def greet()=println("Hello, World !")
如果希望函数返回某个值,但忘了方法定义中的 “=”,Scala 会忽略方法的返回值,而返回 Unit。
在 Scala 中可以省略掉没有参数的方法调用的空括号。
按照惯例,如果调用方法是为了利用方法的“副作用”,此时写上空括号;如果方法没有任何副作用(没有修改其它程序状态),可以省略掉括号。
(3)while循环
var i=0
while (i < args.length) {
println (args(i))
i+=1
}
注意:Scala 不支持++i、i++ 运算,需要使用 i+=1 来自增
扩展:
def approximate(initialGuess: Double) : Double = {
var guess = initialGuess
while(!isGoodEnough(guess))
guess=improve(guess)
guess
}
从简洁度和避免使用 var 变量上看,可以使用函数化编程递归
def approximate(guess: Double) : Double =
if (isGoodEnough(guess)) guess
else approximate(improve(guess))
(4)foreach
使用 while 来实现循环,和使用 Java 实现无太大差异,而 Scala 是面向函数的语言,更好的方法是采用“函数式“风格来编写代码,如下:
args.foreach(arg=>println(arg))
利用 Scala 的缩写形式,如果一个函数只有一个参数并且只包含一个表达式,那么无需明确指明参数,这段代码可以写的更精简些,如下:
args.foreach( println)
(5)for
for(arg<-args)
println(arg)
注意:上述语句中的arg是val类型的
可以在for语句中使用多个过滤器,即添加多个 if 语句
val filesHere = (new java.io.File(".")).listFiles
for( file <-filesHere
if file.isFile
if file.getName.endsWith(".scala")
) println(file)
(6)使用new实例化对象
实例化过程中,可以使用数值或类型作为参数
使用数值实例化
val big=new java.math.BigInteger("123456")
println(big)
使用类型实例化
val greetStrings:Array[String]=new Array[String](3)
greetStrings(0)="Hello"
greetStrings(1)=","
greetStrings(2)="World!\n"
for(i<-0 to 2)
print(greetStrings(i))
注:Array是可变的,Scala访问数组的语法是使用()而非[]。
Array 的 zip 操作符可以用来将两个数组转换成二元组的数组
scala> Array( 1,2,3) zip Array("a","b")
res0: Array[(Int, String)] = Array((1,a), (2,b))
从上述代码可知:zip 分别取两个数组对应的元素组成一个新的二元祖
如果一个数组长度大于另外一个数组,多余的元素被忽略
使用类型作为参数,它的作用类似 Java 的 Generic 类型。
对比如下 Java 代码,可知 Scala 使用方括号来指明类型参数,而非尖括号。
LinkedList number = new LinkedList<Integer>();
(7)上述示例中 for 表达式使用了 0 to 2,其实质是:(0).to(2)。
Scala 中所有基本数据类型都是对象(和 Java 不同),因此 0 可以有方法(实际上调用的是 RichInt 的 to 方法),这种只有一个参数的方法可以使用操作符的写法(不用.和括号)
需要注意的是:该语法只有在明确指定方法调用的接受者时才有效,如:Console println 10
(8)Scala里所有的运算符都是方法调用
1+2
实质上是:(1).+(2)
运算符在 Scala 中并不是什么特殊的语法,任何 Scala 方法都可以作为运算符来使用,是否是运算符取决于你如何使用这个方法
当你使用 s.indexOf(‘o’)时,indexOf 不是一个运算符; 而写成 s indexOf ‘o’时, indexOf 就是一个运算符,因为使用了运算符的语法。
除了类似+的中缀运算符(运算符在两个操作数之间),还有前缀运算符和后缀运算符。
顾名思义,前缀运算符在操作数前面,比如 -7 中的“-”;后缀运算符在操作数的后面,比如 7 toLong 中的 toLong。
前缀和后缀运算符都使用一个操作数,而中缀运算符使用前后两个操作数。
Scala 中实现前缀和后缀运算符的方法都以 unary_-开头;比如: 表达式 -2.0 实际上调用 (2.0).unary_- 方法。
扩展;
Scala 的==和 Java 不同,scala 的==只用于比较两个对象的值是否相同,而对于引用类型的比较使用另外的操作符 eq 和 ne。
scala> val x =new String("abc")
x: String = abc
scala> val y =new String("abc")
y: String = abc
scala> x == y
res0: Boolean = true
scala> x eq y
res1: Boolean = false
scala> x ne y
res2: Boolean = true
(9)用括号给变量传递一个或多个值参数时,Scala会把它转换成对apply方法的调用
这说明了为什么 Scala 使用()来访问数组元素:
在 Scala 中,数组和其它普通类一样,没有什么特别之处,前述示例中的 greetStrings(i) 被转化为 greetStrings.apply(i);
(10)当对带有括号并包括一到若干参数的变量赋值时,将调用变量的update方法,并以括号里的值和等号右边的对象作为参数
如:greetStrings(0)="Hello" 将被转化为 greetStrings.update(0,"Hello")
故前述示例可以写为如下方式:
val greetStrings =new Array[String](3)
greetStrings.update(0,"Hello")
greetStrings.update(1,",")
greetStrings.update(2,"world!\n")
for(i <- 0 to 2)
print(greetStrings.apply(i))
(11)List-不可变的同类对象序列,其索引基于0
Scala 中数组的元素是可以被修改的,如果需要使用不可修改的序列,Scala 提供了 Lists。
List 提供了一个 :: 方法用来向 List 中添加一个元素,:: 方法(操作符)是右操作符,也就是使用 :: 右边的对象来调用它的 :: 方法
val oneTowThree = 1 :: 2 ::3 :: Nil
println(oneTowThree)
Scala 规定所有以 : 开头的操作符都是右操作符,如果你自己定义以 : 开头的方法(操作符)也是右操作符
对某个列表调用方法时,似乎这个列表发生了改变,而实际上只是用新的值重建了列表然后再返回
Nil是空列表的简写
省略方法介绍
扩展:
面向函数的编程语言的一个特点是调用某个方法不应该有任何副作用:参数一定,调用方法后,返回一定的结果,而不去修改程序的其它状态(副作用)。
这样做的一个好处是方法和方法之间关联性较小,从而方法变得更可靠,且重用性高。
这个原则意味着变量需要设成不可修改的,进而避免了多线程的互锁问题。
(12)元组(Tuple)-不可变,可包含不同类型的元素,其索引基于1
Tuple 在方法需要返回多个结果时非常有用,可以使用 ._ 或者 索引 来访问元组的元素
val pair=(99,"Luftballons")
println(pair._1)
println(pair._2)
元组的实际类型取决于它的分量的类型,比如上面 pair 的类型为 Tuple2[Int, String],而 (‘u’, ’r’, ”the”, 1, 4, ”me”) 的类型为 Tuple6[Char, Char, String, Int, Int, String]。
目前 Scala 的元组支持的最大长度为 22,如果有需要,可以自己扩展更长的元组。
(13)特质(trait)
该概念接近于Java的接口(interface),所不同的是 Scala 中的 Trait 可以有方法的实现
(14)集(set)
Scala 提供了两种 Sets 类,分两个包定义 Mutable (可变)和 Immutable (不可变),使用同样名称的 Trait
如果使用可修改的集合类( Set 类型),需要使用全路径来指明 Set,如:scala.collection.mutalbe.Set。
缺省情况下 Set 为 Immutable Set。
不可变:
var tempSet=Set("he","she")
tempSet+="it"
println(tempSet.contains("kk"))
将上例中的 var 改为 val 会出现错误,代码如下,
val tempSet=Set("he","she")
tempSet+="it"
println(tempSet.contains("kk"))
错因:对不可变集使用+=,会对 tempSet 重新赋值,因此应该定义变量为var
可变:
import scala.collection.mutable.Set val tempSet=Set("he","she")
tempSet+="it"
println(tempSet.contains("kk"))
该处使用val却不会出现问题
(15)映射(map)
Scala 提供了 Mutable 和 Immutable 两种 Map 类型
用->和+=方法向Map里添加键值对
val romanNumeral = Map ( 1 -> "I", 2 -> "II", 3 -> "III", 4 -> "IV", 5 -> "V")
println (romanNumeral(2))
(16)任何对象都能调用->方法,并返回包含键值对的二元组
隐式转换
(17)
Scala 引入包的方式和 Java 类似,也是通过 import 语句。
如果需要引入多个类,Scala 使用 “_” 而非 “*”。
和 Java 相比,Scala 的 import 的使用更加灵活:
- 可以出现在文件中任何地方
- 可以 import 对象(singleton 或者普通对象)和 package 本身
- 支持对引入的对象重命名或者隐藏某些类型
使用=>重命名类型,如:
重新定义包名称
import java.{sql => S}
除 String 类型定义在 java.lang 包中,其它类型都定义在包 scala 中。
Scala的每个源文件都隐含了对包java.lang、包scala,以及单例对象Predef的成员引用,可以使用直接使用 Int,Short,String等,而无需再引入包或是使用全称。
StringBuilder 类定义在 scala 包和 java.lang 包中,后定义的 import 会覆盖前面的,因此如果不明确指明,StringBuilder 为 scala.StringBuilder 而非 java.lang.StringBuilder。
扩展:
Scala支持如下两种方式将代码放入包中:
A、
package shop.navigation
class Navigator
B、
package shop.navigation {
class Navigator
}
第二种方法可以在一个文件中定义多个包。
(18)try-catch
Scala 的异常处理和 Java 类似,一个方法可以通过抛出异常而终止
Scala 捕获异常的方法:
import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException
try {
val f = new FileReader("input.txt")
} catch {
case ex: FileNotFoundException => //handle missing file
case ex: IOException => //handle other I/O error
}
Scala 的 try-catch 可以返回结果,如下示例:
import java.net.URL
import java.net.MalformedURLException
def urlFor(path:String) =
try {
new URL(path)
} catch {
case e: MalformedURLException =>
new URL("http://www.scala-lang.org")
}
Scala 的 finally 语句不管 try 块是否抛出异常,都会执行,所以可以在 finally 块中添加代码以关闭已经打开的文件。
(19)match
Scala 的 match 表达式支持从多个选择中选取其一,类似 Java 中的 switch 语句。
val firstArg = if (args.length >0 ) args(0) else ""
firstArg match {
case "salt" => println("pepper")
case "chips" => println("salsa")
case "eggs" => println("bacon")
case _ => println("huh?")
}
上述代码和 Java 的 switch 相比有几点不同:
A、任何类型的常量都可以用在 case 语句中
B、case 语句无需使用 break
C、缺省匹配为”_”,其作用类似 java 中的 default
scala 的 match 表达式可以有返回值,如下:
val firstArg = if (args.length >0 ) args(0) else ""
val friend = firstArg match {
case "salt" => "pepper"
case "chips" => "salsa"
case "eggs" => "bacon"
case _ => "huh?"
}
(20)
脚本必须以结果表达式结束
(21)Scala编译器
Scala的基本编译器:scalac
快速Scala编译器:fsc 停止fsc后台进程:fsc -shutdown
Scala学习笔记(三):基础知识的更多相关文章
- Scala学习笔记--正则表达式基础知识、如何在scala内使用
正则表达式语法:https://msdn.microsoft.com/zh-cn/library/ae5bf541(VS.80).aspx 基础知识:正则表达式30分钟入门教程 http://www. ...
- C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)
一:值类型和引用类型的含义参考前一篇文章 C#学习笔记(基础知识回顾)之值类型和引用类型 1.1,C#数据类型分为在栈上分配内存的值类型和在托管堆上分配内存的引用类型.如果int只不过是栈上的一个4字 ...
- C#学习笔记(基础知识回顾)之值传递和引用传递
一:要了解值传递和引用传递,先要知道这两种类型含义,可以参考上一篇 C#学习笔记(基础知识回顾)之值类型和引用类型 二:给方法传递参数分为值传递和引用传递. 2.1在变量通过引用传递给方法时,被调用的 ...
- C#学习笔记(基础知识回顾)之值类型和引用类型
一:C#把数据类型分为值类型和引用类型 1.1:从概念上来看,其区别是值类型直接存储值,而引用类型存储对值的引用. 1.2:这两种类型在内存的不同地方,值类型存储在堆栈中,而引用类型存储在托管对上.存 ...
- Quartz学习笔记:基础知识
Quartz学习笔记:基础知识 引入Quartz 关于任务调度 关于任务调度,Java.util.Timer是最简单的一种实现任务调度的方法,简单的使用如下: import java.util.Tim ...
- MyBatis:学习笔记(1)——基础知识
MyBatis:学习笔记(1)--基础知识 引入MyBatis JDBC编程的问题及解决设想 ☐ 数据库连接使用时创建,不使用时就释放,频繁开启和关闭,造成数据库资源浪费,影响数据库性能. ☐ 使用数 ...
- .net学习笔记---xml基础知识
一.XML简介 XML是一种标记语言,用于描述数据,它提供一种标准化的方式来来表示文本数据.XML文档以.xml为后缀.需要彻底注意的是XML是区分大小写的. 先从一个简单的XML例子来了解下xml基 ...
- (C/C++学习笔记) 一. 基础知识
一. 基础知识 ● 程序和C/C++ 程序: 根据Wirth (1976), Algorithms + Data Structures = Programs. Whence C: 1972, Denn ...
- C#学习笔记(基础知识回顾)之枚举
一:枚举的含义 枚举是用户定义的整数类型.在声明一个枚举时,要指定该枚举的示例可以包含的一组可接受的值.还可以给值指定易于记忆的名称.个人理解就是为一组整数值赋予意义. 二:枚举的优势 2.1:枚举可 ...
- 数据库学习笔记 - MySQL基础知识
一.数据库基础知识 1.1 Whats's 数据库 数据库(Database,DB):将大量数据保存起来,通过计算机加工而成的可以进行高效访问的数据集合.如:大型-银行存储的信息,小型-电话簿. 数据 ...
随机推荐
- mxnet数据操作
# coding: utf-8 # In[2]: from mxnet import nd # In[3]: x = nd.arange(12) x # In[4]: x.shape,x.size # ...
- [SCOI2014]方伯伯运椰子
嘟嘟嘟 01分数规划思维题. 题中要求交通总量不减少,那么如果总量增加的话,总费用就会增加,所以一定不是更优的解.那么总量守恒. 这是不是就想到了网络流?对于每一个节点流入量等于流出量.然后就是很有思 ...
- 将 form 参数转换为 json 绑定 datagrid 上
$.fn.serializeJson=function(){ var serializeObj={}; var array=this.serializeArray(); var str=this.se ...
- EF Ccore 主从配置 最简化
业务需要 配置一主多从数据库 读写分离 orm用的ef core , 把思路和代码写下 1. 配置2个数据库上下文 ETMasterContext ETSlaveContext(把增删改功能禁用掉 ...
- Feign Form表单POST提交
Form表单的POST提交,调用该类接口最长用的方式就是HttpClient,如果使用Feign,如何实现呢? 首先,看下Http中已Form的形式做Post提交的定义: -------------- ...
- C#中的代码书写规范以及命名规范
C#代码书写规则: 1. 尽量使用接口,然后使用类实现接口,以提高程序的灵活性. 2.一行不要超过80个字符 3.尽量不要手动更改计算机生成的代码 4.关键的语句写注释 5.建议局部变量在最接近使用它 ...
- 实现虚拟(Virtual)DOM
Virtual DOM算法 把一个div元素的属性打印出来,如下: 可以看到仅仅是第一层,真正DOM的元素是非常庞大的,这也是DOM加载慢的原因. 相对于DOM对象,原生的JavaScript对象处理 ...
- 史上最简单的SpringCloud教程 | 第三篇: 服务消费者(Feign)(Finchley版本)
转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springcloud/2018/08/30/sc-f3-feign/ 本文出自方志朋的博客 上一篇文章,讲述了如 ...
- 分享一个带有合计行功能的DataGridView扩展
因为一个Winform的项目中需要用到带有合计行的表格,并且需要满足以下需求: 合计行可自动对需要求和的列进行求和计算; 合计行必须固定(冻结)在表格的最底部,且其位置不受滚动条的滚动而移动; 可以设 ...
- 经验之谈—控制器的view的显示
经验之谈—控制器的view的显示 开发中,我们经常需要将一个控制器的view添加到另一个控制器的view上,这种效果是我们期望看到的,但是里边隐藏着一些细节,不注意的话,可能会达不到我们想到的效果. ...