美文网首页
Scala入门

Scala入门

作者: 学术界末流打工人 | 来源:发表于2020-02-01 15:15 被阅读0次

基础

Scala 不要求必须写;号作为一句代码的结束标志。

变量

W3Cschool scala教程-变量

Scala 中三种方式定义把变量
Scala允许您在声明它时决定变量是否是不可变的(只读)

  • val
  • var
  • 延迟的 val

val 使用该关键字修饰的变量是不可变的(不可重新被赋值)。

val x = 10

var使用该关键字的的变量是可变的。

var x = 10

延迟val变量计算一次,第一次访问变量。只有vals可以是惰性变量。

object Main {
  def main(args: Array[String]) {
        val x = 10e20 
        println(x);
  }
}

变量声明

w3school scala教程-变量声明

Scala允许您在声明它时确定变量是不可变的(只读的)还是不可变的(读写的)。

val array: Array[String] = new Array(5) 

例子
数组元素本身是可变的,因此可以修改元素:
注意:在声明时必须初始化val。

object Main {
  def main(args: Array[String]) {

     val array: Array[String] = new Array(5) 
     array = new Array(2) 
     array(0) = "Hello" 
     println(array )
  }
}

可变变量
可变变量用关键字 var 声明,并且必须立即初始化。

object Main {
  def main(args: Array[String]) {

     var stockPrice: Double = 100.0 
     stockPrice = 200.0 
     println(stockPrice);
  }
}

例子
下面的代码定义了一个具有不可变的名字和姓氏,但是一个可变的年龄的Person类

class Person(val name: String, var age: Int) 

object Main {
  def main(args: Array[String]) {

     val p = new Person("Dean Wampler", 29) 
     println(p.name)
     println(p.age )
     p.age = 30
     println(p.age )

  }
}

注释

单行注释

单行注释用//开头,并继续到行尾:

// This is a single line comment

多行注释

多行注释以/开头,以/结束。

/*
    This is a multiline comment:
*/

数据类型

数据类型层次结构(官网)

Any是所有类型的超类型,也称为顶级类 型。它定义了一些通用的方法如equalshashCodetoStringAny有两个直接子类:AnyValAnyRef

AnyVal代表值类型。有9个预定义的非空的值类型分别是:DoubleFloatLongIntShortByteCharUnitBooleanUnit是不带任何意义的值类型,它仅有一个实例可以像这样声明:()。所有的函数必须有返回,所以说有时候Unit也是有用的返回类型。

AnyRef代表引用类型。所有非值类型都被定义为引用类型。在Scala中,每个用户自定义的类型都是AnyRef的子类型。如果Scala被应用在Java的运行环境中,AnyRef相当于java.lang.Object

布尔类型

布尔类型限于文本true或文本false,如下面的示例所示。

 val x = false 

字符类型

字符常量用单引号编写,区别于使用双引号写的字符串常量。

// 字符
val x = 'X'
// 字符串
val x = "X"

字符串

Scala的String构建在Java的String上,并向Java的String添加了字符串插值等附加功能。

val hello = "Hello"

字符串插值

字符串插值是一种将字符串中的值与变量组合的机制。
Scala中的插值符号是在字符串的第一个双引号之前添加的s前缀。
然后可以使用美元符号运算符$引用变量。

 // creating a String 
 val bookTitle = "Scala" 
 // String interpolation 
 println(s"Book Title is ${ bookTitle}" );

数字类型

Scala中的数字数据类型构成了Float和Double类型以及诸如Byte,Short,Int,Long和Char等整数数据类型。

下表显示Scala的数值数据类型。

数据类型 描述
Byte 从-128到127范围内的整数
Short 从-32768到32767范围内的整数
Int 从-2147483648到2147483647范围内的整数
Long 从-9223372036854775808到9223372036854775807范围内的整数
Float 最大正有限浮点是3.4028235 * 1038,最小正有限非零浮点是1.40 * 10-45
Double 最大正有限双是1.7976931348623157 * 10308,最小正有限非零双是4.9 * 10-324

例子
Scala可以按顺序自动将数字从一种类型转换为另一种类型。

值类型转换
Byte . Short . Int . Long . Float . Double. 

其中字节类型是最低的,并且可以转换为任何其他类型,如以下示例所示:

val x: Byte = 30 

我们可以将x赋值为Short类型,如下例所示:

val y: Short = x 

同样,我们可以将x赋值为Int,Long,Float,Double,Scala会自动转换数字,如下例所示:

val z: Double = y 

Scala不允许以前面提到的顺序自动转换。

var hello: Byte = 30
// 执行下面自动类型顺序转换时会报错: Byte类型和Double类型不匹配
hello = 30.0

常量值

整数常量

数值常量范围表

目标类型 最低(含) 最大(包括)
Long -2^{63} 2^{63}
Int -2^{31} 2^{31} - 1
Short -2^{15} 2^{15}
Char 0 2^{16}
Byte -2^{7} 2^{7} - 1

注意:对于长文本,需要在文本末尾附加L或l字符,除非将值分配给声明为Long的变量。 否则,推断Int

// 该段报错,默认识别为nt类型
var long = 922337203685477580
// 该段报错,即使变量定义为Long类型,也默认识别为Int
var l :Long = 922337203685477580

// 正确声明方式
var long = 922337203685477580L
var l: Long = 922337203685477580L

浮点常量

注意
对于 Float 常量,在文字末尾附加F或f字符。否则,假定为Double
指数部分的格式为e或E,后跟可选的+或 - ,后跟一个或多个数字

.14 
3.14 
3.14f 
3.14F 
3.14d 
3.14D 
3e5 
3E5 
3.14e+5 
3.14e-5 
3.14e-5 
3.14e-5f 
3.14e-5F 
3.14e-5d 
3.14e-5D 

布尔常量

val b1 = true 
val b2 = false 

字符常量

字符常量是可打印的Unicode字符或转义序列,写在单引号之间。
Unicode值介于0和255之间的字符可以由八进制转义表示,即反斜杠(\)后跟最多三个八进制字符的序列。

"A" 
"\u0041"  // "A" in Unicode 
"\n" 
"\012"    // "\n" in octal 
"\t" 

字符串常量

在字符串中包含双引号“字符,必须使用\ 字符“转义"

"This is a\ntest" 
"He said, \"SQL is for database!\"" 
"First\tSecond" 

由双引号的三元组界定的字符串常量称为多行字符串常量
这些字符串可以覆盖几行。换行符将是字符串的一部分。它们可以包括任何字符,包括一个或两个双引号在一起,但不能三个在一起

"""This is a \ntest""" 

"""He said, "SQL is for database!" """ 

"""First line\n 
Second line\t 
Fourth line""" 

在代码中使用多行字符串时,要使用String.stripMargin缩进子字符串以进行正确的代码格式化。
它删除子字符串中的所有空格,直到并包括垂直条|的第一次出现。
要添加空格缩进,请将空格放在|后面。

val name = ray
def hello(name: String) = s"""Welcome! 
       Hello, $name! 
       * (Star!!) 
       |Hi. 
       |    whitespace.""" .stripMargin

/* 输出结果
 Welcome!
       Hello,ray!
       * (Star!!)
Hi.
    whitespace.
*/

删除字符串中前缀或后缀,则有相应的前缀和stripSuffix方法

val name = "ray"
val s :String = s"""xxxGoodbye, ${name}yyy
         | xxxCome again!yyy""".stripMargin .stripPrefix("xxx").stripSuffix("yyy")

/* 
输出
Goodbye, rayyyy
 xxxCome again! 
*/

符号常量

Scala有符号类型,它们是内部连接的字符串,意味着具有相同“名称”的两个符号实际上是指内存中的同一个对象。

符号常量是单引号',后跟一个或多个数字,字母或下划线(“_”),但第一个字符不能是数字。

函数常量 (未解释清楚)

(i:Int,s:String)=> s + i 是Function2类型的函数文本[Int,String,String](返回String)
以下声明是等效的:

val f1: (Int,String) => String       = (i, s) => s+i 
val f2: Function2[Int,String,String] = (i, s) => s+i 

元组常量

val t1: (Int,String)       = (1, "two") 
val t2: Tuple2[Int,String] = (1, "two")

// 元组参数调用
//表达式t._n从元组t中检索第n个项,从一个开始,不是零,遵循历史约定。
val t = ("Hello", 1, 2.3)
println( "Print the whole tuple: " + t )
println( "Print the first item:  " + t._1 )
println( "Print the second item: " + t._2 )
println( "Print the third item:  " + t._3 )

空值类型

Nothing是所有类型的子类型,也称为底部类型。没有一个值是Nothing类型的。它的用途之一是给出非正常终止的信号,如抛出异常、程序退出或者一个无限循环(可以理解为它是一个不对值进行定义的表达式的类型,或者是一个不能正常返回的方法)。

Null是所有引用类型的子类型(即AnyRef的任意子类型)。它有一个单例值由关键字null所定义。Null主要是使得Scala满足和其他JVM语言的互操作性,但是几乎不应该在Scala代码中使用。我们将在后面的章节中介绍null的替代方案。

选项

Option 允许我们在没有null“hack”的情况下显式地表达空值。

Option是一个抽象类,它的两个具体子类是Some,当我们有一个值,而None,当我们没有。

val stateCapitals = Map( 
       "Alabama" -> "Montgomery", 
       "Alaska"  -> "Juneau", 
       "Wyoming" -> "Cheyenne") 

println( "Get the capitals wrapped in Options:" ) 
println( "Alabama: " + stateCapitals.get("Alabama") ) 
println( "Wyoming: " + stateCapitals.get("Wyoming") ) 
println( "Unknown: " + stateCapitals.get("Unknown") ) 

println( "Get the capitals themselves out of the Options:" ) 
println( "Alabama: " + stateCapitals.get("Alabama").get ) 
println( "Wyoming: " + stateCapitals.get("Wyoming").getOrElse("Oops!") ) 
println( "Unknown: " + stateCapitals.get("Unknown").getOrElse("Oops2!") )

/* 输出
Get the capitals wrapped in Options:
        Alabama: Some(Montgomery)
        Wyoming: Some(Cheyenne)
        Unknown: None
Get the capitals themselves out of the Options:
        Alabama: Montgomery
        Wyoming: Cheyenne
        Unknown: Oops2!
*/

注意
Map.get方法返回一个Option [T] ,在这种情况下 T是String。

通过返回一个选项,我们不能“忘记”我们必须验证返回的东西。

如果 OptionSome ,则 Some.get返回值。

如果 Option 实际上是 None ,那么 None.get 将抛出一个NoSuchElementException异常。

在最后两个println语句中的getOrElse返回 Option中的值,如果它是一个 Some实例,或者返回传递给getOrElse的参数,如果它是一个 None实例。getOrElse参数作为默认返回值。

范围Range

// 打印 1,2,3,4,5  包含上下限  左闭右闭
println( 1 to 5 )

// 打印 1,2,3,4  包含下限单不包含上限   左闭右开
println( 1 until 5 )

// 定义带步长,每四步打印一次
// 1,5,9,13,17
println( 1 to 20 by 4 )


/*
  几个特殊例子
*/
val v3 = 1L to 10L by 3         // Long 
// 1, 4, 7, 10
println(v3)
    
val v4 = 1.1f to 10.3f by 3.1f  // Float with an interval != 1 
// 1.1, 4.2, 7.2999997
println(v4)

val v5 = 1.1f to 10.3f by 0.5f  // Float with an interval < 1 
// 1.1, 1.6, 2.1, 2.6, 3.1, 3.6, 4.1, 4.6, 5.1, 5.6, 6.1, 6.6, 7.1, 7.6, 8.1, 8.6, 9.1, 9.6, 10.1
println(v5)

val v6 = 1.1 to 10.3 by 3.1     // Double 
// 1.1, 4.2, 7.300000000000001
println(v6)

val v7 = 'a' to 'g' by 3          // Char 
// a, d, g
println(v7)

val v8 = BigInt(1) to BigInt(10) by 3 
// 1, 4, 7, 10
println(v8)
     
val v9 = BigDecimal(1.1) to BigDecimal(10.3) by 3.1 
// 1.1, 4.2, 7.3
println(v9)

元组

元组是具有相同或不同类型的两个或更多个值的有序容器
与列表和数组不同,没有办法迭代元组中的元素

我们可以通过两种方式创建一个元组:

  • 通过用逗号分隔的值写入值,并用一对括号括起来
  • 通过使用关系运算符->
// 以下代码显示了一个包含Int,一个布尔值和一个String的元组,使用前一个方法。
val tuple = (1, false, "Scala")

// 以下代码显示了使用关系运算符创建的元组:
val tuple2 ="title" -> "Beginning Scala"

// 元组的单个元素可以通过其索引访问,其中第一个元素具有索引1。
val tuple = (1, false, "Scala")
// 以下代码显示了访问元组的第三个元素。
val third = tuple._3

单元类型

单元类型用于定义不返回数据的函数。它类似于Java中的void关键字
单元常量是一对空圆括号, ()。

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

语句

条件运算符

运算符 操作 描述
&& 运算符左侧和右侧的值为true。仅当左侧为真时,右侧才被计算。
|| 左侧或右侧的至少一个值为true。仅当左边为假时才计算右侧。
> 大于 左侧的值大于右侧的值。
>= 大于或等于 左侧的值大于或等于右侧的值。
< 少于 左侧的值小于右侧的值。
<= 小于或等于 左侧的值小于或等于右侧的值。
== 等于 左侧的值与右侧的值相同。
!= 不等于 左侧的值与右侧的值不同。

注意
在Java中,==仅比较对象引用。它不会执行逻辑等同性检查,即比较字段值。使用 equals 方法。

Scala使用==作为逻辑等式,但它调用equals方法。当您想要比较引用,但不测试逻辑时,可以使用新的方法 eq

条件判断if

// 基础判断
if (exp) println("yes")

// 三元组判断方式
val i: Int = if (exp) 1 else 3

// 代码块嵌套
val i: Int = if (exp)
                1
             else {
                val j = System.currentTimeMillis
                (j % 100L).toInt
             }

循环语句

for 循环

// 最基本for循环,类似于java1.5后支持的增强for循环
val books = List("Scala", "Groovy", "Java", "SQL", "CSS")
for (book<-books)
  println(book)

// <- 这种方式也叫生成器表达式
for (i <- 1 to 10) println(i) 

// 约束: 过滤值
// 我们可以添加if表达式来过滤我们想要保留的元素。
val dogBreeds = List("D", "Y", "D", "S", "G", "P") 
for (breed <- dogBreeds 
       if breed.contains("D") 
     ) println(breed) 

//多约束
for (breed <- dogBreeds 
       if breed.contains("D") 
       if  !breed.startsWith("Y") 
     ) println(breed)

// 可变绑定
// 我们可以为表达式定义变量。
// 然后我们可以在你的for表达式的正文中重用这些变量。
val books = List("Scala", "Groovy", "Java", "SQL", "CSS")
for {
  book <- books
  bookVal = book.toUpperCase()
} println(bookVal)  //bookVal没有声明为val,但是你仍然可以重用它

/*
Yielding
在Scala的for表达式中,我们可以使用yield关键字来生成新的集合。
从for表达式生成的集合的类型从迭代的集合的类型推断。
要在for循环中将值赋给我们的程序的另一部分,请使用yield关键字为表达式生成新的集合。
*/

val books = List("Scala", "Groovy", "Java", "SQL", "CSS")
var scalabooks = for{
  book <-books
  if book.contains("Scala")
}yield book
println(scalabooks);

while 循环

// 基本用法和其他语言一直
while(true){
  println("hello")
}

// do-while 也与其他语言一直
do { 
  count += 1 
  println(count) 
} while (count < 10)

异常捕获try语句

Scala中的异常处理以不同的方式实现,但它的行为与Java完全相同,并与现有的Java库无缝协作。
Scala中的所有异常都未选中;没有检查异常的概念。
抛出异常在Scala和Java中是一样的。

throw new Exception("some exception...")

// try/finally结构在Scala和Java中也是一样的,如下面的代码所示。
try {
    throw newException("some exception...")
} finally{
    println("This will always be printed")
}

// 异常捕获
// Scala中的异常可以在catch块中进行模式匹配,而不是为每个不同的异常提供单独的catch子句。
try {
    file.write(stuff)
} catch{
    case e:java.io.IOException => // handle IO Exception
    case n:NullPointerException => // handle null pointer
}

模式匹配

def printNum(int: Int) {
  int match {
    case 0 => println("Zero")
    case 1 => println("One")
    // _表示默认匹配  default
    case _ => println("more than one")
  }
}
printNum(0)
printNum(1)
printNum(2)

// 匹配任何类型,传入object,判断类型
def test2(in: Any) = in match {
    case s: String => "String, length "+s.length
    case i: Int if i > 0 => "Natural Int"
    case i: Int => "Another Int"
    case a: AnyRef => a.getClass.getName
    case _ => "null"
}

References

  1. W3Cschool Scala 教程
  2. Scala 官网中文文档

相关文章

网友评论

      本文标题:Scala入门

      本文链接:https://www.haomeiwen.com/subject/nmuzthtx.html