@wuzhimang
2017-08-12T15:49:43.000000Z
字数 9816
阅读 1621
博客
博客链接: http://codeshold.me/2017/07/scala_tour_note.html
因实习,需要了解数据分析方面的知识,需要学习Spark、Scala,花了一天的时间过了一下scala教程(总结即是本文),但个人推荐先从《快学Scala+中文版》这本书开始看(正在看...)这个更适合入门…… 无奈自己后知后觉了……
Tour 学习链接(自己主要是看中文):
1. TOUR OF SCALA (scala-lang.org)
2. Scala教程 (runoob.com)
def main(args: Array[String])
, Scala程序从main()方法开始处理Scala 使用 package 关键字定义包, 将代码定义到某个包中有两种方式
package com.swf
class HelloWorld
------------------------
package com.swf {
class HelloWorld
}
Scala 使用 import 关键字引用包。默认情况下,Scala 总会引入 java.lang._
、 scala._
和 Predef._
,这里也能解释,为什么以scala开头的包,在使用时都是省去scala。
import java.awt.Color // import Color
import java.awt._ // import all the members
import java.awt.{Font, Color} // import members via selector 选择器
import java.until.{HashMap => JavaHashMap} // rename members
import java.util.{HashMap => _, _} // 引入util包的所有成员,但是HashMap被隐藏
def handle(evt: event.ActionEvent) {
Color.
}
Unit
表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()
Nothing
类型在Scala的类层级的最低端;它是任何其他类型的子类型。Any
是所有其他类的超类AnyRef
类是Scala里所有引用类(reference class)的基类字面量 进一步了解
0.0, 0f, 1.0e100
true, false
'<标识符>
这种字面量被映射成预定义类scala.Symbol
的实例, 符号字面量除了显示名字之外,什么都不能做'\n', "hello", """hello"""
字符、字符串、多行字符 scala.Null
类型。 scala.Null
和scala.Nothing
是用统一的方式处理Scala面向对象类型系统的某些"边界情况"的特殊类型。Null类
是null引用对象的类型,它是每个引用类(继承自AnyRef的类)的子类。Null不兼容值类型。
val myVal : String = "Foo" // 申明常量,值不能修改
var myVar : String = "Foo" // 申请变量,值可以修改
// 变量类型申明
var VariableName : DataType [= Initial Value]
val VariableName : DataType [= Initial Value]
// 变量类型引用
var myVar = 10
val myVal = "hello, scala!"
// 多变量申明
val xmax, ymax = 100
val pa = (40, "Foo")
--------
scala> val x, y = 1, 2 // 和python不同 !!!!!!
<console>:1: error: ';' expected but ',' found.
val x, y = 1, 2
^
scala> val x, y = (1, 2)
x: (Int, Int) = (1,2)
y: (Int, Int) = (1,2)
scala> val x, y = 1
x: Int = 1
y: Int = 1
Scala 访问修饰符基本和Java的一样,分别有:private,protected,public
private[x], protected[x]
这里的x指代某个所属的包、类或单例对象。如果写成private[x],读作"这个成员除了对[…]中的类(或[…]中的包中的类)及它们的伴生对象可见外,对其它所有类都是private
。
package bobsrockets{
package navigation{
private[bobsrockets] class Navigator{ // 对bobsrockets中的对象都可见,其他则是private
protected[navigation] def useStarChart(){
class LegOfJourney{
private[Navigator] val distance = 100
}
private[this] var speed = 200
}
package launch{
import navigation._ // import all members
object Vehicle{
private[launch] val guide = new Navigator
}
}
}
}
}
运算符
scala> -8 >>> 1 // 无符号右移!!! 多了个这个
res6: Int = 2147483644
scala> 8 >>> 1
res7: Int = 4
控制语句
if(...){...}else if(){...}else{...}
while(...){...};
, do{...}while(...);
, for(...){...}
<-
用于为变量赋值, to, until, if, yield
object Test {
def main(args: Array[String]) {
var a = 0;
val numList = List(1, 2, 3, 4, 5, 6, 7)
for ( a <- 1 to 10 ) {
}
for ( a <- 1 to 3; b <- 1 to 3) {
}
for ( a <- 1 until 10 ) { //不包含10
}
for ( a <- numList ) { // 循环集合
}
for ( a <- numList if a != 3; if a < 8 ) { // 循环中的过滤
println("Value of a :" + a)
}
// 可以将for循环中的返回值作为一个变量存储
var retVal = for{ a <- numList if a != 3; if a < 8 } yield a
for( a <- retVal ) {
println("!!!value of a :" + a)
}
}
}
基本概念
def functionName([para list]) : [return type] = { function body; return [expr] }
, 如果不写=
和方法的主体,则方法会被隐世的声明为抽象,包含它的类型于是也是一个抽象类型
object add {
def addInt( a:Int, b:Int ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
def printMe() : Unit = {
println("hello world!")
}
}
函数概念解析 runnob.com
传名调用(call-by-name): Scala解释器支持两种--call-by-value
和call-by-name
object Test {
def main(args: Array[String]) {
println(delay(time()))
}
def time() = {
println("richie")
}
def delay(t: => Long) = { // => 设置传名调用 (放在变量名和变量类型中间)
println("wfshi")
t
}
指定函数参数名, 可变参数, 默认参数, 递归, 嵌套
object Test {
def main(args: Array[String]) {
printInt(b=5, a=3) // 制定参数名
printStrings("richie", "wf", "shi")
println("F(5)" + factorial(5))
println("addInt" + addInt())
}
def printInt(a: Int, b: Int) {
println("Value of a :" + a)
}
// 可变参数
def printStrings(args: Sting*) = {
var i: Int = 0
for(arg <- args) {
println("Arg value" + i + arg)
i += 1
}
}
// 递归
def factorial(n: BigInt): BigInt = {
if (n <= 1)
1 // 无return
else
n * factorial(n-1)
}
// 默认参数值
def addInt(a:Int = 5, b:Int = 7) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
// 函数嵌套
def factorial(i: Int) {
def fact(i: Int, accumulator: Int): Int = {
if (i <= 1)
accumulator // 无return
else
fact(i-1, i*accumulator)
}
fact(i, 1)
}
匿名函数
// 匿名函数
var inc = (x:Int) => x+1 // 下面的简写
def add2 = new Function1[Int,Int] {
def apply(x:Int):Int = x+1
}
var x = inc(7)-1
// 可定义多个函数
var mul = (x: Int, y: Int) => x*y
// 可以不设置参数
var userDir = () => {System.getProperty("user.dir")}
高阶函数: higher-order function 操作其他函数的函数; 匿名函数
object Test{
def main(args: Array[String]){
println(apply(layout, 10))
}
// 函数 f 和 值 v 作为参数,而函数 f 又调用了参数 v
def apply(f: Int => String, v: Int) = f(v)
def layout[A](x: A) = "[" + x.toString() + "]"
偏应用函数: 一种表达式,不需要提供函数需要的所有参数,只需要提供部分,或不提供所需参数。
import java.util.Date
object Test{
def main(args: Array[String]) {
val date = new Date
// 下划线替换缺失的参数列表, 并把这新的函数值的索引赋值给变量
val logWriteDataBound = log(date, _: String)
logWithDateBound("message1")
logWithDateBound("message2")
}
def log(data: Date, message: String) = {
println(date + "----" + mesage)
}
currying 函数科里化: 将原来接受两个参数的函数变成新的接受一个参数的函数的过程
def add(x:Int, y:Int) = x+y
def add(x:Int)(y:Int) = x+y // currying, (y:Int)=>1+y
闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。
object Test {
def main(args: Array:[String]) {
println("muliplier(1) value = " + multiplier(1))
println("muliplier(2) value = " + multiplier(2))
}
var factor = 3
val multiplier = (i:Int) => i * factor // 定义了一个匿名函数,并赋值给multiplier
val greeting:String = "Hello World!"; // 不可变
val buf = new StringBuilder; buf += 'a'; // 可变
"a".length
"a".length()
"a".concat("b")
"a" + "b"
printf("%s %d"...) // 格式化输出
数组 常用方法
var z:Array[String] = new Array[String](3)
var z = new Array[String](3)
z(0) = "richiewfshi"; z(1) = "richie"; z(2) = "wfshi"
var z = Array("richie", "wf", "shi")
z.length
// 多维数组
var richieMatrix = ofDim[Int](3,3)
richieMatrix(i)(j) = "xx"
var my = concat(mylist1, mylist2)
import Array._
var mylist3 = range(1, 100, 50)
// 使用数组方式之前需要 import Array._
集合操作
针对不可变集合类的每次操作都会返回一个新的集合,同时使原来的集合不发生改变
val x = List(1, 2, 3, 4)
val x = Set(1, 3, 5, 7)
val x = Map("one" -> 1, "two" -> 2, "three" -> 3) // !!!
scala> val mymap = {"key1" -> 1; "key2" -> 2}
mymap: (String, Int) = (key2,2)
val t = new Tuple3(1, 3.14, "richie") //Tuple3[Int, Int, String]类型,支持的元组最大长度为22
val t = (1, 3, "wfs")
// Tuple.productIterator() 迭代输出元组的所有元素
t.productIterator.foreach(i => println("Value = " + i)
(1, 2, "swf").toString // Tuple.toString() 将元素组合成一个字符串
(1, 2).swap
val sum = x._1 + x._2
val x:Option[Int] = Some(5) // 定义Option, Option[T] 表示有可能包含值的容器,也可能不包含值。
迭代器
Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法。常用方法
val it = Iterator("richie", "wf", "shi") // 用于检测集合中是否还有元素。
while(it.hasNext) {
println(it.next()) // 返回迭代器的下一个元素,并且更新迭代器的状态。
}
val itmax = it.max
val itmin = it.min
val itlen = it.length
val itsize = it.size
Option
Scala Option(选项)类型用来表示一个值是可选的(有值或无值)。
Option[T]
是一个类型为 T 的可选值的容器: 如果值存在, Option[T] 就是一个 Some[T]
,如果不存在, Option[T] 就是对象 None
。常用方法
val myMap: Map[String, String] = Map("key1" -> "value")
val value1: Option[String] = myMap.get("key1") // Some("value")
val value2: Option[String] = myMap.get("key2") // None
// 通过模式匹配来输出匹配值
val res = show(myMap.get("key1"))
def show(x: Option[String]) = x match {
case Some(s) => s
case None => "?"
}
val a:Option[Int] = Some(5)
val b:Option[Int] = None
b.getOrElse(0); b.getOrElse(5) // 都返回默认值5
a.isEmpty
类和对象
Scala继承一个基类跟Java很相似, 但我们需要注意以下几点:
class Location(override val xc: Int, override val yc: Int,
val zc: Int) extends Point(xc, yc) {
...
}
// Scala重写一个非抽象方法,必须用override修饰符
class Employee extends Person {
var salary = 0.0
override def toString = super.toString + "[salary=" + salary + "]"
}
Trait(特征)
Scala的类只能够继承单一父类,但是如果是 Trait(特征) 的话就可以继承多个,从结果来看就是实现了多重继承
trait Equal {
def isEqual(x: Any): Boolean
def isNotEqual(x: Any): Boolean = !isEqual(x)
}
class Point(xc: Int, yc: Int) extends Equal {
var x: Int = xc
var y: Int = yc
def isEqual(obj: Any) =
obj.isInstanceOf[Point] &&
obj.asInstanceOf[Point].x == x
}
object Test {
def main(args: Array[String]) {
val p1 = new Point(2, 3)
val p2 = new Point(2, 4)
println(p1.isNotEqual(p2))
}
}
提取器是从传递给它的对象中提取出构造该对象的参数。
=>
隔开了模式和表达式。使用了case关键字的类定义就是就是样例类(case classes),样例类是种特殊的类,经过优化以用于模式匹配
def matchT(x: Int): Int = x match {
case 1 => "one"
case 2 => "two"
}
def matchTest(x: Any): Any = x match {
case 1 => "one"
case "two" => 2
case y: Int => "scala.Int"
case _ => "many"
}
val alice = new Person("Alice", 25)
for(person <- List(alice, bob, charlie)) {
person match {
case Person("Alice", 25) => println("Hi Alice")
case Person("Bob", 25) => println("Hi Bob")
}
}
// 样例类
case class Person(name: String, age: Int)
正则表达式 实例参考
import scala.util.matching.Regex
object Test{
def main(args: Array[String]) {
// val pattern = "scala".r
val pattern = new Regex("(S|s)cala")
val str = "scala is Scalable and Cool"
println((pattern findFirstIn str).mkString(",")) //使用逗号,连接返回结果
文件写操作,直接使用java中的I/O类
import java.io._
object Test {
def main(args: Array[String]) {
val writer = new PrintWriter(new File("test.txt"))
writer.write("richiewfshi")
writer.close()
}
}
屏幕上读取用户输入
object Test {
def mian(args: Array[String]) {
val line = Console.readLine
println("richie" + line)
文件读操作
import scala.io.Source
object Test {
def main(args: Array[String]) {
Source.fromFile("richie").foreach{
}
}
}
throw new IllegalArgumentException
抛出异常
在Scala里,借用了模式匹配的思想来做异常的匹配,因此,在catch
的代码里,是一系列case字句
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 execption")
}
case ex: IOException => {
println("IO Exception")
}
} finally { // 都需要执行
println("Existing finally...")
}