Scala介绍

scala

scalable language, 可伸缩语言。Scala是一门综合了面向对象和函数式编程概念的静态类型的编程语言。

优点

  • 函数式编程(函数的地位是和整数、字符串等是相同的)
  • 高阶面向对象(每个值都是对象,每个操作都是方法调用)
  • 类型推断

运行

  • 标准的java平台
  • 与所有java类库无缝协作
brew cask install java8
brew install scala
╭─qihao@MacBook-Pro.local ~/Desktop/learn/scala
╰─➤  scala
Welcome to Scala 2.12.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_202).
Type in expressions for evaluation. Or try :help.
// 退出
scala> :quit
// test.scala
object HelloWorld {
  def main(args: Array[String]) {
    println("Hello, world!")
  }
}
// run
╭─qihao@MacBook-Pro.local ~/Desktop/learn/scala
╰─➤  scala test.scala
Hello, world!

语法

循环

args.foreach((arg: String) => println(arg))
args.foreach(arg => println(arg))
/*
foreach的参数是函数字面量(function literal),语法:
(x: Int, y: Int) => x+y
*/
for (arg <- args)
	println(arg)
for (i <- 0 to 2)
	println(i)
for (
	file <- files 
	if file.isFile
	if file.getName.endWith(".scala")
	line <- lines
	)println(file + ": " + line)

match

val firstArg = if (!args.isEmpty) args(0) else ""
val friend = 
	firstArg match {
		case "salt" => "pepper"
		case "eggs" => "bacon"
		case _ => "huh?"
	}
println(friend)
/*
$scala test.scala eggs
bacon
$scala test.scala xxx 
huh?
*/
import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException

try {
  val f = new FileReader("/home/hadoop/input.txt")
} catch {
  case ex: FileNotFoundException => //handle missing file
  case ex: IOException => //handle other I/O error
}

函数

scala支持一等函数。不仅可以定义并调用,还可以用匿名的字面量来编写函数并将它们作为值传递

// 函数定义
def max(x: Int, y: Int): Int = {
	if (x>y) x
	else y
}
// 字面量
var inc = (x: Int) => x+1
inc(1) // 2
// 占位符_ 用来表示一个或多个参数,可以匹配任何对象,
// 只要满足每个参数只在函数字面量出现一次即可
nums.filter((x: Int) => x > 0)
nums.filter(x => x > 0)
nums.filter(_ > 0)
nums.sortWith(_ > 0) // decent
// _ + _ 将会展开成一个接受二个参数的函数自面量
val f = (_: Int) + (_: Int)
f(5,10) // 15
// 变长参数
def echo (args: String *) =
	for (arg <- args) println(arg)
echo ("Hello","World")
Hello
World
val arr= Array("What's","up","doc?")
echo(arr) // error: type mismatch;
// 通过在变量后面添加 _* 来解决。这个符号告诉 Scala 编译器,在传递参数时,逐个传入数组的每个元素,而不是数组整体。
echo (arr: _*)
// 函数参数
def filesMatching(qurey: String, matcher: (String, String) => Boolean) = {
	for (file <- files; if matcher(file.getName, query))
		yield file
}
def filesEnding(query: String) = 
	filesMatching(query, _.endsWith(_))
/*
字面量_.endWith(_)等价于
(fileName: String, query: String) => fileName.endWith(query)
因为这二个参数在函数体分别只用到一次,可以用占位符语法来写
*/
def filesMatching(matcher: String => Boolean) = {
	for (file <- files; if matcher(file.getName))
		yield file
}
def filesEnding(query: String) = 
	filesMatching(_.endsWith(query))

// 柯里化函数
// 柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,返回接受余下的参数而且返回结果的新函数的技术。
def plainOldSum(x:Int,y:Int) = x + y
def curriedSum(x:Int)(y:Int) = x + y 
// 当你调用 curriedSum (1)(2) 时,实际上是依次调用两个普通函数(非柯里化函数),第一次调用使用一个参数 x,返回一个函数类型的值;第二次使用参数 y 调用这个函数类型的值。
def first(x:Int) = (y:Int) => x + y
val second=first(1) // second: Int => Int = <function1>
val onePlus = curriedSum(1)_ // 下划线 _ 作为第二参数列表的占位符, 这个定义的返回值为一个函数,当调用时会给调用的参数加一。

// 无参数()可以省略
"hello".length

数据类型

基础类型

Byte、Short、Int、Long、Char、String、Float、Double、Boolean。

String 插值

// s插值器对内嵌的表达式求值
val name = "qihao"
println(s"Hello, $name, ${1+2}")  //Hello, qihao, 3
println(raw"No\\\space") // No\\\space
println(f"${math.Pi}%.5f") // 3.14159

变量

  • var 可以修改
  • val 不可修改
  • 函数式编程倾向于用val
  • 多行输入用 | 连接,类似于c的\

数组

  • Array 可以修改
val s = new Array[String](3)
s(0) = "hello" // 底层会调用以下方法
s.update(0, "Hello") 
val s2 = Array("0", "1", "2") // 底层会调用以下方法
val s3 = Array.apply("3", "4", "5") 
/*
会调用apply()方法,创建数据并返回,类似与java类中有一个apply的静态方法
*/
  • List 不可修改
// ::: 用于拼接, :: 在已有列表的最前面添加元素
val x = List(1, 2)
val y = List(3, 4)
val z = x ::: y  // List(1, 2, 3, 4)
val zz = 0 :: z  //  List(0,1,2,3,4)
zz.map(s => s+1) // List(1, 2, 3, 4, 5)

tuple,set,map

// tuple 不可变,可以容纳不同类型的元素
val pair = (100, "hello")
println(pair._1)
// set
var set = Set("hello", "world")
set += "qihao" // Set(hello, world, qihao)
// map
val map = Map(1->"hello", 2->"world")
map(2)  // world

类与对象

单例对象

scala 类中不允许有静态成员,于是有了singleton,关键字object
scala类将默认定义为 public 。类的方法以 def 定义开始,要注意的是scala的方法的参数都是 val类型

// 单例对象和类公用一个名字,单例对象称为这个类的伴生对象,类叫做单例对象的伴生类。它们之间可以互相访问对方的私有成员。
// 可以将单例对象当做用于安置那些用java时打算编写的静态方法。
class Test{
}
object Test {
	def xxx() = {} 
}
Test.xxx()
// 重载*符号
def * () {}
// ++ 拼接二个数组
def above(that: Element): Element = 
    new ArrayElement(this.contents ++ that.contents)
// zip 从它的二个操作元中取出对应元素,责成一个pair的数组
new ArrayElement {
    for ( (line1, line2) <- this.contents zip that.contents
        yield line1 + line2
}

重载

class Rational (n:Int, d:Int) {
   require(d!=0)
   private val g =gcd (n.abs,d.abs) 
   val numer =n/g 
   val denom =d/g 
   override def toString = numer + "/" +denom
   def +(that:Rational)  =
     new Rational( 
       numer * that.denom + that.numer* denom,
       denom * that.denom 
     ) 
   // val x = new Rational(1, 2)
   // x+1
   def + (i:Int) =
     new Rational (numer + i * denom, denom)
   
   def * (that:Rational) =
     new Rational( numer * that.numer, denom * that.denom)
   def this(n:Int) = this(n,1) 
   private def gcd(a:Int,b:Int):Int =
     if(b==0) a else gcd(b, a % b)
}
/* 如果 Int 类型能够根据需要自动转换为 Rational 类型,那么 3 + x 就可以相加。Scala 通过 implicit def 定义一个隐含类型转换,比如定义由整数到 Rational 类型的转换如下:
*/
implicit def intToRational(x:Int) = new Rational(x)
// val x = new Rational(1, 2)
// 1+x
/*
其实此时 Rational 的一个 + 重载方法是多余的, 当Scala计算 2 + r ,发现 2(Int) 类型没有可以和 Rational 对象相加的方法,Scala 环境就检查 Int 的隐含类型转换方法是否有合适的类型转换方法,类型转换后的类型支持 + r ,一检查发现定义了由 Int 到 Rational 的隐含转换方法,就自动调用该方法,把整数转换为 Rational 数据类型,然后调用 Rational 对象的 + 方法。从而实现了 Rational 类或是 Int 类的扩展。
*/

继承

支持多继承, class A extends B with C with D

abstract class Element { 
  // 无参数()可以省略, 成员 contents 使用了没有定义具体实现的方法来定义,这个方法称为——“抽象方法”。
  def contents: Array[String]  
  val height = contents.length 
  val width = if (height == 0) 0 else contents(0).length 
}
class ArrayElement(conts: Array[String]) extends Element {
  def contents: Array[String] = conts
}
// Scala 中成员函数和成员变量地位几乎相同,而且也处在同一个命名空间。也就是说,Scala 中不允许定义同名的成员函数和成员变量,但带来的一个好处是,可以使用成员变量来重载一个不带参数的成员函数。
class ArrayElement(conts: Array[String]) extends Element {
    val contents: Array[String] = conts //  val 重载无参数的方法
}
// 与上等价。Scala 支持使用参数化成员变量,也就是把参数和成员变量定义合并到一起来。
class ArrayElement(val contents: Array[String]) extends Element {
}
/*
Scala 支持的两个命名空间如下:
- 值(字段,方法,包还有单例对象)
- 类型(类和 Trait 名)
*/
// 有时你可能不希望基类的某些成员被子类重载。和 Java 类似,在 Scala 中也是使用 final 来修饰类的成员。
class ArrayElement extends Element { 
  final override def demo() { 
    println("ArrayElement's implementation invoked") 
  } 
}

trait

可以用extends或with关键字混入(mix in)类中,并非继承。
Trait 的概念类似于Java中的 Interface,所不同的是Scala中的 Trait 可以有方法的实现。

trait xx {
}
class xxx extents xx {
}
// 和 Interface 类似,你可以为某个类添加多个 Trait 属性。此时,使用多个 with 即可,比如:
class Animal
trait Philosophical
trait HasLegs 

class Frog extends Animal with Philosophical with HasLegs{
  override def toString="green"
}

其他

import

包是用来分类管理类文件的,包相当于文件夹,而类则相当于文件。

//easy access to Fruit
import bobsdelights.Fruit

//easy access to all members of bobdelights
import bobsdelights._

//easy access to all member of Fruits
import bobsdelights.Fruits._

// rename
import Fruits.{Apple=>MaIntosh,Orange}

// 默认为每个文件添加如下几个 package 。这几个包无需明确指明。
import java.lang._   //everything in the java.lang package
import scala._       //everything in the scala package
import Predef._      //everything in the Predef object

参考文献

  • Martin,Lex Spoon,Bill Venners. Programming in Scala.
  • https://www.shiyanlou.com/courses/490
  • https://zhuanlan.zhihu.com/p/25561741
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值