Scala 学习资源

Scala 这么好的语言为什么不流行

结论:Java 人才更多且成本更低。

Scala 工具

sbt

sbt new 无法处理替换过的 SSH 会导致 Auth fail,一个 workaround 就是手动 clone 项目然后:

sbt new file:///path/to/template.g8

sbt 国内加速

~/.sbt/repositories:

[repositories]
local
nexus-aliyun:https://maven.aliyun.com/nexus/content/groups/public
nexus-aliyun-ivy:https://maven.aliyun.com/nexus/content/groups/public/, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]
typesafe: https://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext], bootOnly

Unique Scala

Rust from Scala

Rust 和 Scala 有很多想通的地方,Rust 应该从 Scala 借鉴了很多:

  • 可变量和不可变量
  • 模式匹配
  • Trait

内置类型

val b: Byte = 1
val x: Int = 1
val l: Long = 1
val s: Short = 1
val d: Double = 2.0
val f: Float = 3.0

字符串拼接

Python 也支持类似的 f-string 语法,在 Scala 中是 s-string 语法。

val firstName = "John"
val mi = 'C'
val lastName = "Doe"

val name = firstName + " " + mi + " " + lastName
val name = s"$firstName $mi $lastName"
println(s"Name: $firstName $mi $lastName")
println(s"Name: ${firstName} ${mi} ${lastName}")
println(s"1+1 = ${1+1}")

多行字符串

Multiline strings

for 循环

val nums = Seq(1,2,3)
for (n <- nums) println(n)

val people = List(
	"Bill",
	"Candy",
	"Karen",
	"Leo",
	"Regina"
)


for (p <- people) println(p)

// foreach
people.foreach(println)


// map foreach

val ratings = Map(
	"Lady in the Water"  -> 3.0,
	"Snakes on a Plane"  -> 4.0,
	"You, Me and Dupree" -> 3.5
)

for ((name,rating) <- ratings) println(s"Movie: $name, Rating: $rating")

ratings.foreach {
	case(movie, rating) => println(s"key: $movie, value: $rating")
}

for 表达式

val nums = Seq(1,2,3)
val doubledNums = for (n <- nums) yield n * 2 // <----- 注意 yield

see also: yield

模式匹配

Rust 和 Scala 很像,但是 Scala 依然有很多独特的地方:

// 模式匹配作为方法体
def convertBooleanToStringMessage(bool: Boolean): String = bool match {
	case true => "you said true"
	case false => "you said false"
}

// alternate cases
def isTrue(a: Any) = a match {
	case 0 | "" => false
	case _ => true
}

// 支持 if
count match {
	case 1 => println("one, a lonely number")
	case x if x == 2 || x == 3 => println("two's company, three's a crowd")
	case x if x > 3 => println("4+, that's a party")
	case _ => println("i'm guessing your number is zero or less")
}

异常捕获

异常捕获结合了模式匹配:

var text = ""
try {
	text = openAndReadAFile(filename)
} catch {
	case e: FileNotFoundException => println("Couldn't find that file.")
	case e: IOException => println("Had an IOException trying to read that file")
}

方法定义

// 函数定义的基本语法
def sum(a: Int, b: Int): Int = a + b
def concatenate(s1: String, s2: String): String = s1 + s2

// 返回参数可以省略
def sum(a: Int, b: Int) = a + b
def concatenate(s1: String, s2: String) = s1 + s2

// 代码块用 {} 包围,但是 = 不能省略
def long(a: Int, b: Int) = {
  a + b
}

类构造

class Person(var firstName: String, var lastName: String)
val p = new Person("Bill", "Panner")

// val 只读
class Person(val firstName: String, val lastName: String)

// 构造方法直接写在类体里
class Person(var firstName: String, var lastName: String) {

	println("the constructor begins")

	// 'public' access by default
	var age = 0

	// some class fields
	private val HOME = System.getProperty("user.home")

	// some methods
	override def toString(): String = s"$firstName $lastName is $age years old"

	def printHome(): Unit = println(s"HOME = $HOME")
	def printFullName(): Unit = println(this)

	printHome()
	printFullName()
	println("you've reached the end of the constructor")
}

// 其他一些例子
class Pizza (var crustSize: Int, var crustType: String)

// a stock, like AAPL or GOOG
class Stock(var symbol: String, var price: BigDecimal)

// a network socket
class Socket(val timeout: Int, val linger: Int) {
	override def toString = s"timeout: $timeout, linger: $linger"
}

class Address (
	var street1: String,
	var street2: String,
	var city: String,
	var state: String
)

构造方法重载

val DefaultCrustSize = 12
val DefaultCrustType = "THIN"

// the primary constructor
class Pizza (var crustSize: Int, var crustType: String) {

	// one-arg auxiliary constructor
	def this(crustSize: Int) = {
		this(crustSize, DefaultCrustType)
	}

	// one-arg auxiliary constructor
	def this(crustType: String) = {
		this(DefaultCrustSize, crustType)
	}

	// zero-arg auxiliary constructor
	def this() = {
		this(DefaultCrustSize, DefaultCrustType)
	}

	override def toString = s"A $crustSize inch pizza with a $crustType crust"

}