Scala - syou2020/memo GitHub Wiki

SDKMAN

sdk install scala

object HelloWorld {
    def main(args: Array[String]): Unit = {
        println("Hello, world!")
    }
} 

$ scalac HelloWorld.scala
$ scala HelloWorld.scala


Scala 特性
面向对象特性
Scala是一种纯面向对象的语言,每个值都是对象。对象的数据类型以及行为由类和特质描述。
类抽象机制的扩展有两种途径:一种途径是子类继承,另一种途径是灵活的混入机制。
这两种途径能避免多重继承的种种问题。

函数式编程
Scala也是一种函数式语言,其函数也能当成值来使用。

静态类型
Scala具备类型系统,通过编译时检查,保证代码的安全性和一致性。

并发性
Scala使用Actor作为其并发模型,Actor是类似线程的实体,通过邮箱发收消息。
Actor可以复用线程,因此可以在程序中可以使用数百万个Actor,而线程只能创建数千个。
在2.10之后的版本中,使用Akka作为其默认Actor实现。

#環境PATH設定
CALA_HOME:D:\Program Files(x86)\scala 

Scala 与 Java 的最大区别是:Scala 语句末尾的分号 ; 是可选的。


scala
:help
:quit


交互式编程(pythonと同じ)
以"$"开头的标识符为保留的 Scala 编译器产生的标志符使用,应用程序应该避免使用"$"开始的标识符,以免造成冲突。

可以在"之间使用任何有效的 Scala 标志符,Scala 将它们解释为一个 Scala 标志符,一个典型的使用为 Thread 的 yield 方法, 在 Scala 中你不能使用 Thread.yield()是因为 yield 为 Scala 中的关键字, 你必须使用 Thread.`yield`()来使用这个方法。

forSome
implicit
lazy
sealed
trait
val
var
yield
-
:
=
=>
<-
<:
<%
>:
#
@

Scala是面向行的语言,语句可以用分号(;)结束或换行符。

定义包
第一种方法和 Java 一样
package com.runoob
class HelloWorld

第二种方法有些类似 C#,可以在一个文件中定义多个包。
package com.runoob {
  class HelloWorld 
}

import java.awt._  // 引入包内所有成员
import java.awt.{Color, Font}
 
// 重命名成员
import java.util.{HashMap => JavaHashMap}
 
// 隐藏成员
import java.util.{HashMap => _, _} // 引入了util包的所有成员,但是HashMap被隐藏了
注意:默认情况下,Scala 总会引入 java.lang._ 、 scala._ 和 Predef._,这里也能解释,为什么以scala开头的包,在使用时都是省去scala.的。

Any是所有其他类的超类
AnyRef类是Scala里所有引用类(reference class)的基类

上表中列出的数据类型都是对象,也就是说scala没有java中的原生类型。在scala是可以对数字等基础类型调用方法的。

符号字面量
符号字面量被写成: '<标识符> 
如: 符号字面量 'x 是表达式 scala.Symbol("x") 的简写


Null类是null引用对象的类型,它是每个引用类(继承自AnyRef的类)的子类。Null不兼容值类型。

在 Scala 中,使用关键词 "var" 声明变量,使用关键词 "val" 声明常量。
声明变量实例如下:
var VariableName : DataType [=  Initial Value]
var VariableName [: DataType] =  Initial Value
var myVar : String = "Foo"
val myVal : String = "Too"


Scala 多个变量声明
val xmax, ymax = 100  // xmax, ymax都声明为100
val pa = (40,"Foo")


Scala 访问修饰符:private,protected,public(默认)

私有(Private)成员
用 private 关键字修饰,带有此标记的成员仅在包含了成员定义的类或对象内部可见,同样的规则还适用内部类。


保护(Protected)成员
因为它只允许保护成员在定义了该成员的的类的子类中被访问

作用域保护
Scala中,访问修饰符可以通过使用限定词强调。格式为:
private[x]
protected[x]
除了对x包中的类及它们的伴生对像可见外,对其它所有类都是private。

private[bobsrockets] class Navigator{
}

Scala 中使用 val 语句可以定义函数,def 语句定义方法。
class Test{
  def m(x: Int) = x + 3
  val f = (x: Int) => x + 3
}
var a = new Test()
a.f(3) # 6
a.m(7) # 10

???
方法声明http://www.runoob.com/scala/scala-functions.html

def functionName ([参数列表]) : [return type]
如果你不写等于号和方法主体,那么方法会被隐式声明为抽象(abstract),包含它的类型于是也是一个抽象类型。

方法定义
def functionName ([参数列表]) : [return type] = {
   function body
   return [expr]
}
如果方法没有返回值,可以返回为 Unit,这个类似于 Java 的 void

1.函数可作为一个参数传入到方法中,而方法不行。
2、在Scala中无法直接操作方法,如果要操作方法,必须先将其转换成函数。有两种方法可以将方法转换成函数:
val f1 = m _
在方法名称m后面紧跟一个空格和下划线告诉编译器将方法m转换成函数,而不是要调用这个方法。 也可以显示地告诉编译器需要将方法转换成函数:
val f1: (Int) => Int = m

new StringBuilder とnew StringBuilder()同じ

var myList = Array(1.9, 2.9, 3.4, 3.5)
      
// 输出所有数组元素
for ( x <- myList ) {
 println( x )
}

// 计算数组所有元素的总和
var total = 0.0;
for ( i <- 0 to (myList.length - 1)) {
 total += myList(i);
}


用 concat() 方法来合并两个数组:concat( myList1, myList2)

创建区间数组:var myList1 = range(10, 20, 2)


????Scala 数组方法
????Scala Iterator(迭代器)http://www.runoob.com/scala/scala-iterators.html



Scala 继承
1、重写一个非抽象方法必须使用override修饰符。
2、只有主构造函数才可以往基类的构造函数里写参数。class Point(xc: Int, yc: Int) {
   var x: Int = xc
   var y: Int = yc

   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
      println ("x 的坐标点: " + x);
      println ("y 的坐标点: " + y);
   }
}

class Location(override val xc: Int, override val yc: Int,
   val zc :Int) extends Point(xc, yc){
   var z: Int = zc

   def move(dx: Int, dy: Int, dz: Int) {
      x = x + dx
      y = y + dy
      z = z + dz
      println ("x 的坐标点 : " + x);
      println ("y 的坐标点 : " + y);
      println ("z 的坐标点 : " + z);
   }
}


import java.io._

class Point(val xc: Int, val yc: Int) {
   var x: Int = xc
   var y: Int = yc
   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
      println ("x 的坐标点 : " + x);
      println ("y 的坐标点 : " + y);
   }
}

class Location(override val xc: Int, override val yc: Int,
   val zc :Int) extends Point(xc, yc){
   var z: Int = zc

   def move(dx: Int, dy: Int, dz: Int) {
      x = x + dx
      y = y + dy
      z = z + dz
      println ("x 的坐标点 : " + x);
      println ("y 的坐标点 : " + y);
      println ("z 的坐标点 : " + z);
   }
}



Scala 单例对象
在 Scala 中,是没有 static 这个东西的,但是它也为我们提供了单例模式的实现方法,那就是使用关键字 object。
Scala 中使用单例模式时,除了定义的类之外,还要定义一个同名的 object 对象,它和类的区别是,object对象不能带参数。
当单例对象与某个类共享同一个名称时,他被称作是这个类的伴生对象:companion object。你必须在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类:companion class。类和它的伴生对象可以互相访问其私有成员。

Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。
与接口不同的是,它还可以定义属性和方法的实现。所以其实 Scala Trait(特征)更像 Java 的抽象类。 
一般情况下Scala的类只能够继承单一父类,但是如果是 Trait(特征) 的话就可以继承多个,从结果来看就是实现了多重继承。
Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait,如下所示:
trait Equal {
  def isEqual(x: Any): Boolean
  def isNotEqual(x: Any): Boolean = !isEqual(x)
}


Scala 模式匹配
match 对应 Java 里的 switch,但是写在选择器表达式之后。即: 选择器 match {备选项}。
def matchTest(x: Int): String = x match {
      case 1 => "one"
      case 2 => "two"
      case _ => "many"
   }
match 表达式通过以代码编写的先后次序尝试每个模式来完成计算,只要发现有一个匹配的case,剩下的case不会继续匹配。

使用样例类
使用了case关键字的类定义就是就是样例类(case classes),样例类是种特殊的类,经过优化以用于模式匹配。
object Test {
   def main(args: Array[String]) {
       val alice = new Person("Alice", 25)
       val bob = new Person("Bob", 32)
       val charlie = new Person("Charlie", 32)
   
    for (person <- List(alice, bob, charlie)) {
        person match {
            case Person("Alice", 25) => println("Hi Alice!")
            case Person("Bob", 32) => println("Hi Bob!")
            case Person(name, age) =>
               println("Age: " + age + " year, name: " + name + "?")
         }
      }
   }
   // 样例类
   case class Person(name: String, age: Int)
}

在声明样例类时,下面的过程自动发生了:
构造器的每个参数都成为val,除非显式被声明为var,但是并不推荐这么做;
在伴生对象中提供了apply方法,所以可以不使用new关键字就可构建对象;
提供unapply方法使模式匹配可以工作;
生成toString、equals、hashCode和copy方法,除非显示给出这些方法的定义。

[Scala 正则表达式](http://www.runoob.com/scala/scala-regular-expressions.html)
import scala.util.matching.Regex

object Test {
   def main(args: Array[String]) {
      val pattern = "Scala".r  # String 类的 r() 方法构造了一个Regex对象
      val str = "Scala is Scalable and cool"
      
      println(pattern findFirstIn str)
   }
}


捕获异常

import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException

object Test {
   def main(args: Array[String]) {
      try {
         val f = new FileReader("input.txt")
      } catch {
         case ex: FileNotFoundException => {
            println("Missing file exception")
         }
         case ex: IOException => {
            println("IO Exception")
         }
      } finally {
         println("Exiting finally...")
      }
   }
}


Scala 提取器(Extractor)
Scala 提取器是一个带有unapply方法的对象。
unapply方法算是apply方法的反向操作:unapply接受一个对象,然后从对象中提取值,
提取的值通常是用来构造该对象的值。

object Test {
   def main(args: Array[String]) {
      
      println ("Apply 方法 : " + apply("Zara", "gmail.com"));
      println ("Unapply 方法 : " + unapply("[email protected]"));
      println ("Unapply 方法 : " + unapply("Zara Ali"));

   }
   // 注入方法 (可选)
   def apply(user: String, domain: String) = {
      user +"@"+ domain
   }

   // 提取方法(必选)
   def unapply(str: String): Option[(String, String)] = {
      val parts = str split "@"
      if (parts.length == 2){
         Some(parts(0), parts(1)) 
      }else{
         None
      }
   }
}

以上对象定义了两个方法: apply 和 unapply 方法。通过 apply 方法我们无需使用 new 操作就可以创建对象。所以你可以通过语句 Test("Zara", "gmail.com") 来构造一个字符串 "[email protected]"。


提取器使用模式匹配
在我们实例化一个类的时,可以带上0个或者多个的参数,编译器在实例化的时会调用 apply 方法。我们可以在类和对象中都定义 apply 方法。
就像我们之前提到过的,unapply 用于提取我们指定查找的值,它与 apply 的操作相反。 当我们在提取器对象中使用 match 语句是,unapply 将自动执行,如下所示:

object Test {
   def main(args: Array[String]) {
      
      val x = Test(5)
      println(x)

      x match
      {
         case Test(num) => println(x + " 是 " + num + " 的两倍!")
         //unapply 被调用
         case _ => println("无法计算")
      }

   }
   def apply(x: Int) = x*2
   def unapply(z: Int): Option[Int] = if (z%2==0) Some(z/2) else None
}
执行以上代码,输出结果为:
$ scalac Test.scala 
$ scala Test
10
10 是 5 的两倍!

object HelloWorld {
    def main(args: Array[String]): Unit = {
        println("Hello, world!")
    }
} 

$ scalac HelloWorld.scala
$ scala HelloWorld.scala


Scala 特性
面向对象特性
Scala是一种纯面向对象的语言,每个值都是对象。对象的数据类型以及行为由类和特质描述。
类抽象机制的扩展有两种途径:一种途径是子类继承,另一种途径是灵活的混入机制。
这两种途径能避免多重继承的种种问题。

函数式编程
Scala也是一种函数式语言,其函数也能当成值来使用。

静态类型
Scala具备类型系统,通过编译时检查,保证代码的安全性和一致性。

并发性
Scala使用Actor作为其并发模型,Actor是类似线程的实体,通过邮箱发收消息。
Actor可以复用线程,因此可以在程序中可以使用数百万个Actor,而线程只能创建数千个。
在2.10之后的版本中,使用Akka作为其默认Actor实现。

#環境PATH設定
SCALA_HOME:D:\Program Files(x86)\scala 
⚠️ **GitHub.com Fallback** ⚠️