scala语法

根据documents记录一些零碎的知识点,学习一定程度后再总结一下。

1 basic

1.1 Variables and Values

Variables和Values分别用var和val表示,他们之间的区别是var可以重复赋值,而val赋值后不可改变,相当于const。

val x = 1+1
var y: Int = 1 + 1
y = 3 

变量的type类似c++11中auto会自己推断,同时也可以显式地标明:

val x: Int = 1+1 

用{}将表达式圈起来就是一个blocks,相当于一个作用域,最后的一行表达式的输出就是blocks的输出:

println({
  val x = 1 + 1
  x + 1
}) // 3

1.2 function

带参数的表达式就是函数。

匿名函数:
()括号内是参数:

(x: Int) => x + 1

named函数:

val getAns = () => 4

单个参数:

val add = (x: Int) => x + 1
println(add(1))

多个参数

val add = (x: Int, y: Int) => x + y

=>右边就是带有参数的表达式

高阶函数

高阶函数:其他函数做参数或者是其结果的函数。

c++只能调用函数指针,来实现上述形式。

def apply(f: Int => String, v: Int) = f(v)

1.3 method

method结构: def关键字,方法名,多个参数列表或者没有参数列表,返回类型,body

def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier

如果返回类型是Unit,那么就表示viod,只是scala每个表达式必须返回一个值,所以用Unit,表示没有什么信息。

1.4 Classes

类的构成:

类名,构造参数

class Greeter(prefix: String, suffix: String) {
  def greet(name: String): Unit =
    println(prefix + name + suffix)
}

val greeter = new Greeter("Hello, ", "!")
greeter.greet("Scala developer") // Hello, Scala developer!
默认构造函数
class Point(var x: Int = 0, var y: Int = 0)
val origin = new Point  // x and y are both set to 0
val point1 = new Point(1)
println(point1.x)  // prints 1

默认构造下只想手动赋值非第一个的参数,需要指明参数名称

class Point(var x: Int = 0, var y: Int = 0)
val point2 = new Point(y=2)
println(point2.y)  // prints 2

private,将变量与类外隔离;与c++类似可以用def方法读取私有变量

private[A]会增加可见范围到A。

val修饰的变量默认为公有的,没有val即为私有;

class Point {
  private var _x = 0
  private var _y = 0
  private val bound = 100
  def x = _x
  def x_= (newValue: Int): Unit = {
    if (newValue < bound) _x = newValue else printWarning
  }
  def y = _y
  def y_= (newValue: Int): Unit = {
    if (newValue < bound) _y = newValue else printWarning
  }
  private def printWarning = println("WARNING: Out of bounds")
}
抽象类:
abstract class Element {  //abstract表示抽象类
    def contents: Array[String]  //没有函数体表示声明抽象方法
}

无参函数和属性, 统一访问模式

abstract class Element {
   def contents: Array[String]  //组合Array[] 
   def height: Int = contents.length //无参函数
   def width: Int = if (height == 0) 0 else contents(0).length
}
//等同于
abstract class Element {
    def contents: Array[String]
    val height = contents.length //属性
    val width = if (height == 0) 0 else contents(0).length
}

1.5 case

该类在类前加case关键字,不可修改并且之间可以比较大小

case 类最基本形式:
case calss + 名字 + 参数列表

实例化不需要new,因为该类有默认的apply方法构造。

case class Message(sender: String, recipient: String, body: String)//变量类型为val public
val message1 = Message("guillaume@quebec.ca", "jorge@catalonia.es", "Ça va ?")//实例化该类不需要new关键字

message1.sender = "travis@washington.us"  // val是immutable的

case实例的比较:比较基于结构而不是引用,虽然两者明显指向的对象不一样,但是仍然可以进行比较。

case class Message(sender: String, recipient: String, body: String)
val message2 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?")
val message3 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?")
val messagesAreTheSame = message2 == message3  // true

case的复制:

case class Message(sender: String, recipient: String, body: String)
val message4 = Message("julien@bretagne.fr", "travis@washington.us", "Me zo o komz gant ma amezeg")
val message5 = message4.copy(sender = message4.recipient, recipient = "claire@bourgogne.fr")
message5.sender  // travis@washington.us
message5.recipient // claire@bourgogne.fr
message5.body  // "Me zo o komz gant ma amezeg"

因为可变和不可变的区别,所以使用val相对case来说更安全。

1.6 Traits

traits相当于Java接口,但是功能更加强大,因为他还可以定义属性和方法。

与generic class和abstract method结合:

trait Iterator[A] {
  def hasNext: Boolean
  def next(): A
}

因为scala的类仅继承单一父类,但是特征却可以多重继承。

extend和with

extend, implicitly inherit the trait’s superclass

class Frog extends Philosophical { //mix in Philosophical trait
    override def toString = "green"//override子类覆写父类方法
}

with, 需要显式的指明超类

class Animal
trait HasLegs
class Frog extends Animal with Philosophical with HasLegs {//继承Animal,并mix in两个traits
    override def toString = "green"
}

1.7 type

类型体系:
这里写图片描述

类型转换顺序:
这里写图片描述

编译时Scala自动对应到Java原始类型,提高运行效率。Unit对应java的void

隐式转换
implicit def foo(s:String):Int = Integer.parseInt(s) // 需要时把String->Int
def add(a:Int, b:Int) = a+b
add("100",8) // 108, 先把"100"隐式转换为100

1.8 各种关键字

1.8.1 require
def f(n:Int) = { require(n!=0, "n can't be zero"); 1.0/n }
1.8.2 application
不带命令行参数的简化main方法:
object app1 extends Application {
    println("hello world")
}
1.8.3 for循环
for (i <- 0 to n) foo(i) // 包含n,即Range(0,1,2,...,n,n+1)
for (i <- 0 until n) foo(i)  // 不包含n,即Range(0,1,2,3,...,n)
1.8.4 reduceLeft /foldLeft /scanLeft
def fac(n: Int) = 1 to n reduceLeft(_*_)
fac(5) // 5*4*3*2 = 120
相当于:
    ((((1*2)*3)*4)*5)
def sum(L: Seq[Int]) = L.foldLeft(0)(_ + _)//累加
def multiply(L: Seq[Int]) = L.foldLeft(1)(_ * _)//累积
List(1,2,3,4,5).scanLeft(0)(_+_) // (0,1,3,6,10,15)
相当于:
(0,(0+1),(0+1+2),(0+1+2+3),(0+1+2+3+4),(0+1+2+3+4+5))

注:
@ (z /: List(a, b, c))(op) 相当于 op(op(op(z, a), b), c)
简单来说:加法用0,乘法用1
@ (List(a, b, c) :\ z) (op) equals op(a, op(b, op(c, z)))
此处省略一万字。。。。。。。。。。。。。。。

1.8 pattern matching

1.8.1 定义

value match expression,起作用类似if else

def matchTest(x: Int): String = x match {
  case 1 => "one"
  case 2 => "two"
  case _ => "many" //类似case中的default
}
matchTest(3)  // many
matchTest(1)  // one
1.8.2 与case class
def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {
  notification match {
    case Email(email, _, _) if importantPeopleInfo.contains(email) =>
      "You got an email from special someone!"
    case SMS(number, _) if importantPeopleInfo.contains(number) =>
      "You got an SMS from special someone!"
    case other =>
      showNotification(other) // nothing special, delegate to our original showNotification function
  }
} 



val importantPeopleInfo = Seq("867-5309", "jenny@gmail.com")
val someSms = SMS("867-5309", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
val importantEmail = Email("jenny@gmail.com", "Drinks tonight?", "I'm free after 5!")
val importantSms = SMS("867-5309", "I'm here! Where are you?")
println(showImportantNotification(someSms, importantPeopleInfo))
println(showImportantNotification(someVoiceRecording, importantPeopleInfo))
println(showImportantNotification(importantEmail, importantPeopleInfo))
println(showImportantNotification(importantSms, importantPeopleInfo))
1.8.3 Matching on type only
abstract class Device
case class Phone(model: String) extends Device{
  def screenOff = "Turning screen off"
}
case class Computer(model: String) extends Device {
  def screenSaverOn = "Turning screen saver on..."
}
def goIdle(device: Device) = device match {
  case p: Phone => p.screenOff
  case c: Computer => c.screenSaverOn
}
1.8.4 Sealed classes
sealed abstract class Furniture
case class Couch() extends Furniture
case class Chair() extends Furniture
def findPlaceToSit(piece: Furniture): String = piece match {
  case a: Couch => "Lie on the couch"
  case b: Chair => "Sit on the chair"//不需要catch all了
}

1.9 Regular Expression Patterns

任何string对象都可以转换成正则表达式:

import scala.util.matching.Regex
val numberPattern: Regex = "[0-9]".r//在string后加.r

1.10 For Comprehensions

for (enumerators) yield e

enumerators:可以是generator,或者是filter;

满足要求的就可以将e加入到一个list中

def foo(n: Int, v: Int) =
   for (i <- 0 until n;
        j <- i until n if i + j == v)
   yield (i, j)
foo(10, 10) foreach {
  case (i, j) =>
    print(s"($i, $j) ")  // prints (1, 9) (2, 8) (3, 7) (4, 6) (5, 5)
}

1.11 Variances

Covariance

如果有class List[+A],则表示该类是covariance。那么如果A是B的subtype,那么List[A]也是List[B]的subtype。

那么就可以在有List[B]的情况下用List[A]替换掉。

Contravariance

如果有class List[-A],那么如果A是B的subtype,那么List[B]是List[A]的subtype。

Invariance

正常情况下,A和B的关系不影响其List之间的关系

type bounds
class PetContainer[P <: Pet](p: P) {
  def pet: P = p
}

[P <: Pet]表示,该类的参数必须是Pet的subtype

1.12 Abstract Types

抽象的type意味着具体的type需要根据实现来定义:

trait Buffer {
  type T
  val element: T//element的类型是T
}

抽象类extends了traits:
SeqBuffer 类的新类型必须是

abstract class SeqBuffer extends Buffer {
  type U
  type T <: Seq[U]
  def length = element.length
}

Compound Types

def cloneAndReset(obj: Cloneable with Resetable): Cloneable = {
  //...
}

Polymorphic Methods

与generic class相似,[A]表示某个type

def listOfDuplicates[A](x: A, length: Int): List[A] = {
    if (length < 1)
        Nil
    else
        x :: listOfDuplicates(x, length - 1)
}
println(listOfDuplicates[Int](3, 4))  // List(3, 3, 3, 3)
println(listOfDuplicates("La", 8))  // List(La, La, La, La, La, La, La, La)

Local Type Inference

类型推断,编译器可以根据表达式进行类型推断,而不用每次都显式地标明。

Polymorphic Methods或者generic class中也可以进行类型推断。

object InferenceTest1 extends App {
  val x = 1 + 2 * 3         // the type of x is Int
  val y = x.toString()      // the type of y is String
  def succ(x: Int) = x + 1  // method succ returns Int values
}

但是如果返回值是一个递归调用方法,那么类型推断将失效。

以下情况类型推断将会出错:

object InferenceTest4 {
  var obj = null
  obj = new Object()
}

By-name Parameters与By-value Parameters

def calculate(input: => Int) = input * 37//By-name

By-name在不需要的时候不会evaluated,
By-value 在一开始就会且仅会evaluated一次。

2 OO

2.1 Generic Classes

将type作为一个参数的类

类名后加[A],将type A作为参数传入

class Stack[A] {//以下操作都只对type A有用
  private var elements: List[A] = Nil
  def push(x: A) { elements = x :: elements }
  def peek: A = elements.head
  def pop(): A = {
    val currentTop = peek
    elements = elements.tail
    currentTop
  }
}

如果type下面还有subtype,那么对于subtype同样适用

class Fruit
class Apple extends Fruit
class Banana extends Fruit
val stack = new Stack[Fruit]
val apple = new Apple
val banana = new Banana
stack.push(apple)
stack.push(banana)

2.2 singleton object

用object代替class
现在,sum可以通过import test .Blah.sum导入了

package test
object Blah {
  def sum(l: List[Int]): Int = l.sum
}

Scala不能定义静态成员, 所以用Singleton对象来达到同样的目的

import ChecksumAccumulator.calculate
  object Summer {
    def main(args: Array[String]) {
      for (arg <args)
        println(arg +": "+ calculate(arg))
    }
}

2.3 继承

超类的私有成员不会被子类继承.
抽象成员, 需要被子类实现(implement)
一般成员, 可用被子类重写(override)

重写方法和属性,两者不能重名,但是可以转换。

参数化属性

class ArrayElement( val contents: Array[String] ) extends Element //实现属性

final成员

加在method前,表示成员函数禁止被任何子类override
加在class前,表示该类禁止被任何子类继承

2.4 Extractor Objects

用法

import scala.util.Random
object CustomerID {
  def apply(name: String) = s"$name--${Random.nextLong}"//apply方法创造一个实例
  def unapply(customerID: String): Option[String] = {
    val name = customerID.split("--").head
    if (name.nonEmpty) Some(name) else None
  }//unapply做了反操作,提取出name
}
val customer1ID = CustomerID("Sukyoung")  // 创造了实例

val customer2ID = CustomerID("Suhal") //等价于val name = CustomerID.unapply(customer2ID).get

val CustomerID(name) = customer2ID//用于赋值


customer1ID match {
  case CustomerID(name) => println(name)  // prints Sukyoung
  case _ => println("Could not extract a CustomerID")
}

返回值

仅仅是测试,返回 Boolen即可;
返回一个子值,返回Option[T];
返回多个子值,返回Option[(T1,…,Tn)]。

None:Option的两个子类之一,另一个是Some,用于安全的函数返回值

数据结构

数组

可变的同类对象序列, 适用于OO场景

val greetStrings = new Array[String](3) //greetStrings为val, 但是内部的数组值是可变的
greetStrings(0) = "Hello"  //greetStrings.apply(0),所以用()
greetStrings(1) = ", "
greetStrings(2) = "world!\n"
//简单初始化
val numNames = Array("zero", "one", "two") 

对应可变的:

val ab = collection.mutable.ArrayBuffer[Int]()
ab += (1,3,5,7)
ab ++= List(9,11) // ArrayBuffer(1, 3, 5, 7, 9, 11)
ab toArray // Array (1, 3, 5, 7, 9, 11)
ab clear // ArrayBuffer()

List

List为不可变对象序列

对于List最常用的操作符为::, cons, 把新的elem放到list最前端
:::, 两个list的合并

Nil:长度为0的List

Queues

import scala.collection.immutable.Queue //不可变Queue

val has1 = empty.enqueue(1)//入队
val has123 = has1.enqueue(List(2, 3)) //添加多个元素
val (element, has23) = has123.dequeue //取出头元素,返回两个值, 头元素和剩下的queue

import scala.collection.mutable.Queue //可变Queue

queue += "a"  //添加单个
queue ++= List("b", "c") //添加多个
queue.dequeue //取出头元素, 只返回一个值

Stacks

import scala.collection.mutable.Stack

Tuple

tuple和list一样是不可变的, 不同是, list中的elem必须是同一种类型, 但tuple中可以包含不同类型的elem

val pair = (99, "Luftballons")
println(pair._1) //从1开始的!

Set和Map

Scala需要兼顾OO和FP, 所以需要提供mutable和immutable版本
默认是Immutable, 如果需要使用mutable版本, 需要在使用前显示的引用

Sorted Set and Map

基于红黑树实现的有序的Set和Map

### Scala 编程语言基础语法教程 #### 变量声明数据类型 Scala 支持两种类型的变量定义:`val` 和 `var`。`val` 定义不可变变量,而 `var` 定义可变变量。 ```scala // 不可变变量 val greeting: String = "Hello" // 可变变量 var count: Int = 0 count += 1 ``` 对于基本的数据类型,Scala 提供了丰富的支持,包括整数 (`Int`)、浮点数 (`Double`)、字符 (`Char`) 和布尔值 (`Boolean`) 等[^3]。 #### 函数定义 函数可以通过关键字 `def` 来定义,并可以接受参数列表以及返回类型说明: ```scala def add(x: Int, y: Int): Int = { x + y } ``` 匿名函数也可以通过简洁的方式创建并传递给其他方法作为参数: ```scala val multiply = (a: Int, b: Int) => a * b println(multiply(4, 5)) ``` #### 类对象 面向对象编程是 Scala 的核心特性之一。类和对象的定义如下所示: ```scala class Person(name: String, age: Int) object ExampleObject { def sayHello(): Unit = println("Hello from object!") } ExampleObject.sayHello() ``` #### 控制结构 常见的控制流语句如条件表达式和循环也得到了良好的支持: ```scala if (condition) { // 执行某些操作 } else { // 处理另一种情况 } for (i <- 1 to 10) { println(i) } ``` #### 集合处理 集合框架提供了多种容器来存储多个元素,比如数组、列表、映射表等: ```scala val numbers = Array[Int](1, 2, 3, 4, 5) numbers.foreach(print) val map = Map("one" -> 1, "two" -> 2) println(map.get("one")) ``` 以上只是对 Scala 基础语法的一个简单介绍,更多高级特性和最佳实践可以在深入学习过程中逐步掌握[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值