Scala语法(一) 基础语法(变量&常量&判断&循环&数组&集合)
前言
在前面的章节中, 我们介绍了如何在Eclipse内安装Scala环境. 本章开始, 我们将讲解下Scala的基本语法.
PS: 1. 个人虽然没有想转Scala语言开发的思想, 但是近来Scala语言被各种媒体炒的火热. 了解下总没有坏处. 就个人而言, 还是非常喜欢Java的简洁语法的.
- 另在学习过程中, Scala经常会去调用Java的语法. 个人感觉, Scala在某些方面做的仍然还没有到位和完全. 但是, 对于Spark等的大数据开发, Scala或许是一门不错的语言.
- Eclipse中的Scala IDE(
Oxygen
)做的仍然不是非常完善. 最需要的查看Scala内的源码的功能缺失, 后期Scala的开发可能会转向使用IDEA进行开发.(虽然, 个人非常不喜欢IDEA那些花里胡哨的所谓自动化功能.) - 本文所涉及的代码, 都可以在我的github项目的https://github.com/SeanYanxml/arsenal 的
arsenal-scala/quick-scala
下找到.
前置准备
Eclipse Scala环境的配置 根据上述的文章配置好相关的开发环境. (IDEA略过此步骤)
Maven的Pom.xml
文件依赖. 由于之前的Maven创建模板内, Scala的某些依赖的版本号已经不适合个人使用的版本. 个人将其替换成了相应的版本. 读者可以根据个人需要, 从 https://mvnrepository.com/ 上查询并选择需要的版本.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yanxml</groupId>
<artifactId>quick-scala</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>${project.artifactId}</name>
<description>My wonderfull scala app</description>
<inceptionYear>2010</inceptionYear>
<licenses>
<license>
<name>My License</name>
<url>http://....</url>
<distribution>repo</distribution>
</license>
</licenses>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<encoding>UTF-8</encoding>
<scala.tools.version>2.11</scala.tools.version>
<scala.version>2.11.8</scala.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.11.8</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId>
<version>2.11.8</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-reflect</artifactId>
<version>2.11.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.scala-lang/scala-actors -->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-actors</artifactId>
<version>2.11.8</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- <dependency> <groupId>org.specs2</groupId> <artifactId>specs2_${scala.tools.version}</artifactId>
<version>3.0</version> <scope>test</scope> </dependency> -->
<!-- https://mvnrepository.com/artifact/org.scalatest/scalatest -->
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest_2.11</artifactId>
<version>3.0.0-M16-SNAP6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest_${scala.tools.version}</artifactId>
<version>3.0.0-M16-SNAP6</version>
<scope>test</scope>
</dependency>
<!-- spark -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>2.2.1</version>
</dependency>
<!-- akka -->
<!-- https://mvnrepository.com/artifact/com.typesafe.akka/akka-actor -->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.11</artifactId>
<version>2.3.14</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.typesafe.akka/akka-remote -->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-remote_2.11</artifactId>
<version>2.3.14</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<!-- see http://davidb.github.com/scala-maven-plugin -->
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.1.3</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
<configuration>
<args>
<arg>-make:transitive</arg>
<arg>-dependencyfile</arg>
<arg>${project.build.directory}/.scala_dependencies</arg>
</args>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.13</version>
<configuration>
<useFile>false</useFile>
<disableXmlReport>true</disableXmlReport>
<!-- If you have classpath issue like NoDefClassError,... -->
<!-- useManifestOnlyJar>false</useManifestOnlyJar -->
<includes>
<include>**/*Test.*</include>
<include>**/*Suite.*</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>
正文
从本节开始, 我们正式介绍Scala的语法.
本章主要介绍如下几个方面:
- QuickStart - HelloWorld
- 常量&变量
- 判断(if)
- 循环(while/for/map)
- 数组(Array)
- 元组(Tuple)
- 集合(Map&List&Set)
HelloWorld
在进行学习之前, 先使用HelloWorld
小程序判断当前的编译器环境是否配置完毕.
在Scala中, 主要有2种方式创建静态的Main方法. def main
&extends scala.APP
.
另外值得一提的是, 这边使用的是object
的前缀, 千万不要使用class
前缀. 这是初学者非常容易犯的错误.(笔者当初就因为这个问题, 以为是IDE环境的问题, 绕了好久. 希望各位引以为戒.)
object App {
def main(args : Array[String]) {
println( "Hello World!" )
}
}
object HelloWorld extends App{
println("HelloWorld")
}
常量&变量
在Scala中, 与Java一样. 也有8种基本数据类型, 但是不存在向Java内的那么复杂. 即不存在基础类与封装类(int & Integer)
的区别. 而是统一的使用基础类.(Byte
Short
Int
Long
Float
Double
Char
Boolean
)
常量的定义使用val
关键字, 变量的定义使用var
关键字. 在定义的过程中, 可以直接指定变量&常量
的数据类型, 也可以不进行指定, 由系统自动识别装配.(var hello = "123"
/ var hello2:String = "hello"
)
@Test
// 常见的变量与常量类型
def variable(){
// 常量
// 使用val修饰的变量值是不可变的,相当于java里用final修饰的变量.
val a = 1
// false. val can not change.
// a = 2
// 变量
// < var a = xx >. scala会自动推断变量的类型.
// < var a : type(Int,String,...) >. 可以通过值得scala变量的类型.
var b1 = 1
var b2: String = "hello"
}
判断(if)
Scala
内的if
判断与Java
中的类似. 但是表达式更加的泛化, 并且可以直接赋值给变量. 并且if
内的返回值可以是多种数据类型的.(详间下方Scala
示例.)
# Java
int a=0;
if(a>0){
a++;
}else{
a--;
}
# Scala
def ifelse(){
println("if---else---test")
val x = 1
// 判断x的值 返回值给y
val y = if(x>0) 1 else -1
println(y)
// 支持混合类型表达式
val z = if(x>2) 1 else "error"
println(z)
// 缺失else 相当于if(x>2) else()
val m = if(x>2) 1
println(m)
// scala中有个Unit类, 相当于Java中的void.
val n = if(x>2) 1 else()
println(n)
val k = if(x<0) 0 else if(x>2) 1 else -1
println(k)
}
代码块(Block)
在Java
中, 代码块是由{}
中的代码体. 在Scala
内也是如此. 唯一不同的是, Scala
内的代码体是可以赋值的.
# Java
public static void main(String[]args){
int a=0;
int b=0;
}
# Scala
@Test
// 块表达式(如何确定block的返回值?)
def block(){
println("block---test")
val x = 0
val result = {
if (x>0) -1 else 1
}
println(result)
}
循环(For&While)
在Java内, 我们经常使用while
/do-while
/for
三种循环体. 在Scala内, 我们也可以使用. 但是Scala中, 更经常使用for
和map()
函数进行循环操作.
# java
public static void main(String []args){
int a=2;
while(a>0){
a++;
}
do{
a++;
}while(a>0)
for(int i=a;i>0;i++){
a++;
}
}
# Scala
@Test
// 常见的for循环
def forcycle(){
println("for---cycle---test")
// 遍历 to 是一个方法
1 to 10
for(i <- 1 to 10){print(i)}
println()
// 数组的定义 (相当于使用数组的Object方法 也就是静态方法)
val arr = Array("a","b","c")
for(a<-arr){print(a)}
println()
// 循环带条件, 主要if判断前没有分号
for(i<- 1 to 3; j<- 1 to 3 if i !=j){
print(10*(i)+j+" ")
}
println()
//for推导式: for的循环的循环体以yield开始, 该循环会构建出一个集合
// 每次迭代生成集合的一个值
val v = for(i<-1 to 10) yield i *10
println(v)
1.to(10).map(_*10)
// 遍历数组
val arr2 = Array(1,2,3)
val t = for(i<-arr2) yield i*2
println(t)
// 偶数 奇数获取
val arrTmp = Array(1,2,3,4,5,6,7,8)
val arrResult = for(i<-arrTmp){if(i%2==0) i else()}
val arrResult2 = for(i<-arrTmp ; if(i%2==0)) yield i
val arrResult3 = for(i<-arrTmp ; if(i%2==0)) i
val arrResult4 = arrTmp.filter(_%2==0)
for(i <- 1 to arrTmp.length) print(arrTmp(i))
for(i <- 0 until arrTmp.length) println(arrTmp(i))
}
Scala do…while 循环
数组&元组
Scala内的数组与Java内数组的定义略有不同. 且插入和删除操作也非常不一样. Scala内通过+
和-
来进行末尾增加和删除单个元素; ++
来增加集合元素. 当然也可以通过insert()
和remove()
函数进行插入和删除多个元素.
#Java
public static void main(String []args){
String []array1= {"1","2","3"};
String []array2 = new String[10];
// 循环遍历1
for(String str:array2){
}
// 循环遍历2
for(int i=0;i<array2.length;i++){
}
}
# Scala
@Test
def initArray(){
// Test1
// 初始化一个长度为8的定长数组, 所有元素均为0
val array1 = new Array[Int](10)
// 直接打印定长数组, 内容为数组的hashcode值
println(array1)
// 将数组转换为缓冲, 可以看到数组内的内容
// to buffer 将数组转换为缓冲
println(array1.toBuffer)
// Test2
// 使用静态方法创建
val array2 = Array[Int](10)
println(array2.toBuffer)
// Test3
val array3 = Array("Hadoop","Strom","Spark")
println(array3(1))
// 变长数组
// 如果想使用数组缓冲,需要导入 import scala.collection.mutable.ArrayBuffer包
val arrayBuffer1 = ArrayBuffer[Int]()
// 尾部追加一个元素 +=尾部追加元素
arrayBuffer1 += 1
// 尾部追加多个元素
arrayBuffer1 += (2,3,4,5)
// 追加一个数组 ++=
arrayBuffer1 ++= Array(6,7)
// 追加一个缓冲数组 ++=
arrayBuffer1 ++= ArrayBuffer(8,9)
// 打印缓冲
println(arrayBuffer1)
// 指定位置添加元素
val arrayBuffer2 = ArrayBuffer[Int]()
arrayBuffer2 += (1,2,3)
// 在数组角标为0的位置 开始插入2个元素
arrayBuffer2.insert(0, -1,0)
// 在数组角标位置为8的位置删除2个雅俗
arrayBuffer2.remove(1,2)
}
/**
* 遍历数组的方式主要有2种
* 1. for循环
* 2. 使用until生成角标, 0 until 10 (包含0不包含10 前封后开)
* 3. map方法
* */
@Test
def foreachArray(){
// 初始化
val array = Array(1,2,3,4,5,6)
// 使用for循环
for(i <- array){
print(i)
}
// 使用角标 (有时候需要获取数组的下标)
// .reverse可以将其进行反转
for(i<-(0 until array.length)){
print(array(i))
}
// 倒转遍历数组
for(i<-(0 until array.length).reverse){
}
// map方式
// 方法转换为一个函数
array.map(println(_))
}
/**
* 转换数组, 生成一个新的数组
* 1. yield方式
* 2. map方法.
* */
@Test
def swapArray(){
val array = Array(1,2,3,4,5)
// 偶数取出来 乘以10
val arrayOdd = for(i<- array;if i%2==0)yield i*10
println(arrayOdd.toBuffer)
// map 方式的隐式函数 (一步一步的简化方式)
array.map((x:Int)=>x*10)
array.map(x=>x*10)
array.map(_*10)
val arrayOddMap = array.filter(_%2==0).map(_*10)
println(arrayOddMap.toBuffer)
}
/**
* 与Array相关的其他方法.
*
* */
@Test
def otherArrayFunction(){
val array = Array(1,3,2,5,5)
// 求和运算
array.sum
// 排序
array.sorted
// 倒叙
array.sorted.reverse
array.sortBy(x=>x)
// 降叙
array.sortWith(_>_)
// 升序
array.sortWith(_<_)
// 写成方法体
array.sortWith((x,y) => (x>y))
array.sortWith((x,y) => (x<y))
}
元组
数组中的元素都是相同元素. 但是要应对不同元素组成的集合. 这在Scala内提供了新的数据集合:元组
.
@Test
def initTuple(){
// Tuple的三个值可以不相同.
val tuple1 = (1,"Spark",2.0)
// 映射和Map是特殊的元组 也就是对偶元组
val pairTuple = ("T",5)
var m = Map(("b",2),("a",10))
m += pairTuple
m += (("A",1),("B",2))
// x y z的方式取值
val tupleXYZ, (x,y,z) = (1,"Spark",2.0)
val array = Array(("a",1),("b",2))
// 转换为对偶元组
array.toMap
// 拉链操作
val arrayZip1 = Array("a","b","c")
val arrayZip2 = Array("1","2","3","4")
// 拉链对应转换. 但是有多的元素则不会再使用.
arrayZip1.zip(arrayZip2)
}
集合
Scala内的常用集合除了数组
和元组
外, 还有List
、Map
和Set
.
值得一提的是, Scala内有可变集合import scala.collection.mutable.HashSet
与不可变集合import scala.collection.immutable.HashSet
.不可变集合多用于多线程中的某些数据的共享.
其基本使用主要如下所示:
/**
* Scala 的集合三大类型: 序列 Seq 集Set 映射Map.
* 所有的集合都扩展自Iterable特质.
* 在Scala中集合有可变(mutable)和不可变(immutable)两种类型.
* immutable类型的集合初始化后即不可改变.(与val关键字不同. 主要用于多线程的常量场景.)
*
*
* */
class QuickCollection {
// Sequence 序列相关操作
@Test
def immutableListOperation(){
val list = List(1,2,3)
// 使用ListBuffer
val listBuffer = ListBuffer(1,2,3)
listBuffer(1) = 200
val newListBuffer = listBuffer.map(_*10)
// 其他操作
val list1 = List(1,2,3)
val list2 = 0::list1
val list3 = list1.::(0)
val list4 = 0+:list1
val list5 = list1.+:(0)
// 将一个元素加入到list后面形成新的集合
val lsit6 = list1 :+3
val list0 = List(4,5,6)
// 两个集合合并成为新的集合
val list7 = list1++list0
val list8 = list1 ++: list0
}
@Test
def mutableListOperation(){
// 构建一个可变列表, 初始有三个元素1,2,3
val list0 = ListBuffer[Int](1,2,3)
// 创建一个空的可变列表
val list1 = new ListBuffer[Int]
// 向list1中追加元素, 注意没有生成新的集合
list1 += 4
list1.append(5)
list1.append(1,2,3,4,5)
list1 ++= list0
val list2 = list1 ++ list0
list0 ++= list1
}
// HashSet 也有Immutable与Muttable 可变与不可变的两个版本.
@Test
def immuttableSetOperation(){
val set1 = new HashSet[Int]()
// 将元素与set1合并成为一个新的set
val set2 = set1 +1
// set中的元素不能重复
val set3 = set1 ++ Set(5,6,7)
val set0 = Set(1,2,3) ++ set1
println(set0.getClass)
}
// 可变的set的相关操作
@Test
def muttableSetOperation(){
// 创建一个可变的HashSet
val set1 = new scala.collection.mutable.HashSet[Int]()
// 向HashSet内添加元素
set1 += 2
// add等价于+=
set1.add(4)
set1 ++= Set(1,3,5)
// 删除一个元素
set1 -= 5
set1.remove(2)
println(set1)
}
// 不可变Map
@Test
def immutableMapOperation(){
val map1 = new HashMap[String, Int]()
}
@Test
def mutableMapOperation(){
val map1 = new scala.collection.mutable.HashMap[String, Int]()
// 向Map内添加元素
map1("spark") =1
map1 += (("hadoop",2))
map1.put("storm", 3)
println(map1)
//从map中移除元素
map1 -= "spark"
map1.remove("hadoop")
println(map1)
}
@Test
def initMap(){
// immutable 不可改变
val map1 = Map("a"->1, "b"->2)
// mutable 可以改变
// import scala.collection.mutable.Map
val map2 = Map("A"->1, "B" ->2)
// 访问和修改映射中的值
map2("A")=2
map2("C")=100
map2+=("D"->999)
map2+=(("F",2))
//import java.util.HashMap
// 载入Java的HashMap
val hm = new HashMap()
val map3 = Map(("a",1),("B",2))
map3.getOrElse("C", "123")
}
}
Reference
[1]. Scala 教程
[2]. Scala:HelloWorld
[3]. Scala(二) 基础语法
还没有评论,来说两句吧...