scala 笔记

 

如果操作列表的话, 请使用 ListBuffer  如:

 val lstBuf = mutable.ListBuffer[String]()

lstBuf += "111"

lstBuf += "22"

 

lstBuf += ("abab", "ddd", "ddd")

lstBuf.toList.foreach(println(_))

 

 


 

常用表达式

if表达式

val isAdult = if (age > 18) 1 else 0

 

循环

while(true) {}

for(i <- 1 to n) {} //[1,n]

for(i <- 1 until n) {} //[1,n)

for(i <- (1 until n).reverse) //反向遍历

for(c <- "Hello World") print(c)

for(i <- 1 to 9; j <- 1 to 9) {}

for(i <- 1 to 100 if i % 2 == 0) println(i) //if守卫

for(i <- 1 to 3) yield i //推导式:构造集合Vector(1, 2, 3)

 

异常,与java类似

try {

    throw new IllegalArgumentException("")

} catch {

    case exception: IllegalArgumentException => println(exception)

} finally {

}

 


 

 

·apply函数

    ·Scala中的apply函数是非常特殊的一种函数,在Scala的object中,可以声明apply函数。而使用“类名()”的形式,其实就是“类名.apply()”的一种缩写。通常使用这种方式来构造类的对象,而不是使用“new 类名()”的方式。

    ·例如,"Hello World"(6),因为在StringOps类中有def apply(n: Int): Char的函数定义,所以"Hello World"(6),实际上是"Hello World".apply(6)的缩写。

    ·例如,Array(1, 2, 3, 4),实际上是用Array object的apply()函数来创建Array类的实例,也就是一个数组。

 

breakable

 

import scala.util.control.Breaks._

 

breakable({

  for (i <- 0 until(10)){

    if(i==7) break()

    println(i)

  }

})

 

any 类型 ()  AnyVal=()

 

 

====

val ages = Map("Leo" -> 30, "Jen" -> 25, "Jack" -> 23)

ages("Leo") = 31  错误: map 是不可变的,里面的值也无法修改

Map 元素的获取, 要使用getOrElse, 直接获取不到时会报异常

ages.getOrElse("leo","default")

 

// 增加多个元素

ages += ("Mike" -> 35, "Tom" -> 40)

// 移除元素

ages -= "Mike"

// 更新不可变的map

val ages2 = ages + ("Mike" -> 36, "Tom" -> 40)

// 移除不可变map的元素

val ages3 = ages - "Tom"

 

SortedMap, LinkedHashMap

// SortedMap可以自动对Map的key的排序

val ages = scala.collection.immutable.SortedMap("leo" -> 30, "alice" -> 15, "jen" -> 25)

 

// LinkedHashMap可以记住插入entry的顺序

val ages = new scala.collection.mutable.LinkedHashMap[String, Int]

ages("leo") = 30

 

 

Scala的getter和setter方法的命名与java是不同的,是field和field_=的方式

 

========

传入可变变量

val s = sum(1 to 5: _*)

  

在Scala中,提供了lazy值的特性,也就是说,如果将一个变量声明为lazy,则只有在第一次使用该变量时,变量对应的表达式才会发生计算。这种特性对于特别耗时的计算操作特别有用,比如打开文件进行IO,进行网络IO等。

 

import scala.io.Source._

lazy val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString

即使文件不存在,也不会报错,只有第一个使用变量时会报错,证明了表达式计算的lazy特性。

 

 

函数没有返回值的成为过程,如:

def fnTest(name: String) {

  print(name)

}

 

====

object通常用于作为单例模式的实现,或者放class的静态成员,比如工具方法

 

==伴生类, 伴生对象

object通常用于作为单例模式的实现,或者放class的静态成员,比如工具方法

object 对象也可以继承抽象方法

// 伴生类和伴生对象必须存放在一个.scala文件之中

// 伴生类和伴生对象,最大的特点就在于,互相可以访问private field

 

==函数传参

  • 传值调用(call-by-value):先计算参数表达式的值,再应用到函数内部;
  • 传名调用(call-by-name):将未计算的参数表达式直接应用到函数内部

在进入函数内部前,传值调用方式就已经将参数表达式的值计算完毕,而传名调用是在函数内部进行参数表达式的值计算的。

这就造成了一种现象,每次使用传名调用时,解释器都会计算一次表达式的值。

 

参数形式: def delayed( t: => Long ) = {}

=>之前为空 ,不指定类型

 

========类内部定义的是方法

 

求为field选择合适的修饰符就好:var、val、private、private[this]

  

====使用类似 java getter, setter

class  Person2(@BeanProperty var name:String){}

 

val p= new Person2("nihao")

p.getName

p.setName("22")

 

==内部类: 

但是与java不同的是,每个外部类的对象的内部类,都是不同的类

demo: 

class Class {

  val students = new ArrayBuffer[Student]();

  class Student(@BeanProperty val name: String) {

  }

 

  def newStudent(name: String): Student = {

    new Student(name)

  }

}

 

val class1 = new Class;

val class2 = new Class;

 

val s1 = class1.newStudent("name1")

class1.students += s1;

 

val s2 = class2.newStudent("name2")

 

 

==========isInstanceOf, asInstanceOf , getClass, classOf

需要使用isInstanceOf判断对象是否是指定类的对象,如果是的话,则可以使用asInstanceOf将对象转换为指定类型

isInstanceOf只能判断出对象是否是指定类以及其子类的对象,而不能精确判断出,对象就是指定类的对象

// 如果要求精确地判断对象就是指定类的对象,那么就只能使用getClass和classOf了

 

 

==继承

跟java一样,scala中同样可以使用protected关键字来修饰field和method,这样在子类中就不需要super关键字,直接就可以访问field和method

// 还可以使用protected[this],则只能在当前子类对象中访问父类的field和method,无法通过其他子类对象访问父类的field和method

 

--调用父类的 constructor

 

class Person(val name: String, val age: Int)

class student(name: String, age: Int, val score: Int) extends Person(name, age) {

  def this(name: String) {

    this(name, 0, 0)

  }

  def this(score: Int) {

    this("abc", 0, score)

  }

}

 

// Scala中,每个类可以有一个主constr uctor和任意多个辅助constructor,而每个辅助constructor的第一行都必须是调用其他辅助constructor或者是主constructor;因此子类的辅助constructor是一定不可能直接调用父类的constructor的

// 只能在子类的主constructor中调用父类的constructor,以下这种语法,就是通过子类的主构造函数来调用父类的构造函数

// 注意!如果是父类中接收的参数,比如name和age,子类中接收时,就不要用任何val或var来修饰了,否则会认为是子类要覆盖父类的field

 

==匿名内部类

 

匿名子类,也就是说,可以定义一个类的没有名称的子类,并直接创建其对象,然后将对象的引用赋予一个变量。之后甚至可以将该匿名子类的对象传递给其他函数。

 

class Person(protected val name: String) {

  def sayHello = "Hello, I'm " + name

}

val p = new Person("leo") {

  override def sayHello = "Hi, I'm " + name

}

 

def greeting(p: Person { def sayHello: String }) {

  println(p.sayHello)

}

 

====trait 特征

使用trait(特征)相当于java中interface+abstract class

 

scala中可以将trait混入到对象中,就是将trait中定义的方法、字段添加到一个对象中,

作用: 给一个对象添加一些额外的行为, 例子:

trait Logger {

    def log(msg:String) = println(msg)

  }

 

  class UserService

 

  def main(args: Array[String]): Unit = {

    val service = new UserService with Logger

    service.log("混入的方法")

  } 

 

trait 责任链(调用链)

 

trait HandlerTrait {

  def handle(data: String) = println("处理数据...")

}

 

trait DataValidHanlderTrait extends HandlerTrait {

  override def handle(data: String): Unit = {

    println("验证数据...")

    super.handle(data)

  }

}

 

trait SignatureValidHandlerTrait extends HandlerTrait {

  override def handle(data: String): Unit = {

    println("校验签名...")

    super.handle(data)

  }

}

 

class PayService extends DataValidHanlderTrait with SignatureValidHandlerTrait {

  override def handle(data: String): Unit = {

    println("准备支付...")

    super.handle(data)

  }

}

 

val service = new PayService

service.handle("支付参数")

 

 结果:

准备支付...

校验签名...

验证数据...

处理数据...

 

 

 

在Scala中,trait也是有构造代码的,也就是trait中的,不包含在任何方法中的代码

// 而继承了trait的类的构造机制如下:

 

1、父类的构造函数执行;

2、trait的构造代码执行,多个trait从左到右依次执行;

3、构造trait时会先构造父trait,如果多个trait继承同一个父trait,则父trait只会构造一次;

4、所有trait构造完毕之后,子类的构造函数执行

 

  class Person { println("Person's constructor!") }

  trait Logger { println("Logger's constructor!") }

  trait MyLogger extends Logger { println("MyLogger's constructor!") }

  trait TimeLogger extends Logger { println("TimeLogger's constructor!") }

  class Student extends Person with TimeLogger with MyLogger {

    println("Student's constructor!")

  }

 

//  Person's constructor!

//    Logger's constructor!

//    TimeLogger's constructor!

//    MyLogger's constructor!

//    Student's constructor!

 

 

=======方法, 函数:

方法是一个以def开头的带有参数列表(可以无参数列表)的一个逻辑操作块,这正如object或者class中的成员方法一样。

函数是一个赋值给一个变量(或者常量)的匿名方法(带或者不带参数列表),并且通过=>转换符号跟上逻辑代码块的一个表达式。=>转换符号后面的逻辑代码块的写法与method的body部分相同。

Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。

 

使用 val 语句可以定义函数,

使用def 语句定义方法。

 

==> SAM 转换, 简单来说就是把只有一个方法的接口转换为匿名方法

  

==> implicit  隐式转换

 

implicit conversion function

 

主要功能: 1. 隐式类型转换, 2,隐式方法(对象)导入

 

隐式转换的发生时机:

隐式类似转化包括: 函数/方法参数类型不匹配时,自动转化参数

隐式方法导入包括: 使用对象的方法不存在时,转换当前对象类型

 

隐式作用域/查找范围:

1.从当前作用域中查找val,var定义的对象

2.从当前类的伴生对象中查找隐式转换

3.从导入的包中查找隐式转化.

 

Scala默认会使用两种隐式转换,一种是源类型,或者目标类型的伴生对象内的隐式转换函数;一种是当前程序作用域内的可以用唯一标识符表示的隐式转换函数

隐式转换

// 1、调用某个函数,但是给函数传入的参数的类型,与函数定义的接收参数类型不匹配(案例:特殊售票窗口)

// 2、使用某个类型的对象,调用某个方法,而这个方法并不存在于该类型时(案例:超人变身)

// 3、使用某个类型的对象,调用某个方法,虽然该类型有这个方法,但是给方法传入的参数类型,与方法定义的接收参数的类型不匹配(案例:特殊售票窗口加强版)

 

 

==> List

 

head::tail  所以"::"的意思是head+tail组成一个新的 List , 注意 tail::head 是错误的, 因为head是一个值

 

Set 默认是无需的, 子类包括 LinkedHashSet, SortedSet

 

 

===>Actor

 

Scala的Actor类似于Java中的多线程编程。但是不同的是,Scala的Actor提供的模型与多线程有所不同。Scala的Actor尽可能地避免锁和共享状态,从而避免多线程并发时出现资源争用的情况,进而提升多线程编程的性能。此外,Scala Actor的这种模型还可以避免死锁等一系列传统多线程编程的问题。

 


 

 

元组的索引从1开始,是因为对于拥有静态类型元组的其他语言,如Haskell和ML,从1开始是传统的设定。

 

可变参数: echo(arr: _*)

这个标注告诉编译器把 arr 的每个元素当作参数,而不是当作单一的参数传给 echo 。

 

SBT:

什么是SBT? SBT = (not so) Simple Build Tool,是scala的构建工具,与java的maven地位相同。其设计宗旨是让简单的项目可以简单的配置,而复杂的项目可以复杂的配置。

 

?SCALA 标识符

字母数字标识符、操作符标识符、混合标识符、字面量标识符

 

—可变集合

var mutableArray = new ArrrayBuffer[int]()

—不可变集合

var arr= new Array[t](5);

 

可变 list

 

val li = ListBuffer[String]()

 

 

set不可改变

var s1 = Setr(1,2,3,4)

 

hashset可变集合

 

var s  = new Mutable.HashSet[int]()

 

scala  转为 Java

kafkaParams.asJava

 

 

 

object 单例对象

 

val 不可变变量, 使用_占位符

 

 

 

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

 

类和对象

 

Scala中的类不声明为public,一个Scala源文件中可以有多个类。

 

class :修饰的称为伴生类;定义在class中的属性都是动态的,用于实例化 的;scala中的class类默认可以传参数,默认的传参数就是默认的构造函数。class 类属性自带getter ,setter方法。使用class时要new (必须new,除非在对象伴生用apply方法【在加载类的时候默认自动调用】已实经例化好),并且new的时候,class中除了方法不执行,其他都执行。

 

object: 修饰的称为伴生对象;定义在object中的属性(字段、方法)都是静 态的,main函数写在里面;scala 中的object是单例对象,相当于java中的工具类,可以看成是定义静态的方法的类.object不可以传参数。使用object时,不用new.

 

Apply方法

       使用此方法时,可以在main函数中不通过new来创建一个对象,即可以不用专门的一次一次地进行实例化,加载创建对象的这个类的时候,会自动调用apply这个方法,类似Java中的static静态块

 

在 Scala 中,是没有 static 这个东西的,但是它也为我们提供了单例模式的实现方法,那就是使用关键字 object。

Scala 中使用单例模式时,除了定义的类之外,还要定义一个同名的 object 对象,它和类的区别是,object对象不能带参数。

当单例对象与某个类共享同一个名称时,他被称作是这个类的伴生对象:companion object。你必须在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类:companion class。类和它的伴生对象可以互相访问其私有成员。

 

 

 

函数如果没有参数可以不传,, 不写括号

 

在 Scala 中,字符串的类型实际上是 Java String,它本身没有 String 类。

 

 

case class

使用了case关键字的类定义就是样例类(case classes),样例类是种特殊的类。实现了类构造参数的getter方法(构造参数默认被声明为val),当构造参数是声明为var类型的,它将帮你实现setter和getter方法。

       样例类默认帮你实现了toString,equals,copy和hashCode等方法。

       样例类可以new, 也可以不用new

如:

case class Student(id: Int, age: Int)

 

var s1= Student(1,1)

var s2=Student(2,22)

println(s2)

————

 

Actor

Actor Model是用来编写并行计算或分布式系统的高层次抽象(类似java中的Thread)让程序员不必为多线程模式下共享锁而烦恼,被用在Erlang 语言上, 高可用性99.9999999 % 一年只有31ms 宕机Actors将状态和行为封装在一个轻量的进程/线程中,但是不和其他Actors分享状态,每个Actors有自己的世界观,当需要和其他Actors交互时,通过发送事件和消息,发送是异步的,非堵塞的(fire-andforget),发送消息后不必等另外Actors回复,也不必暂停,每个Actors有自己的消息队列,进来的消息按先来后到排列,这就有很好的并发策略和可伸缩性,可以建立性能很好的事件驱动系统。

 

Actor的特征:

1.ActorModel是消息传递模型,基本特征就是消息传递

2.消息发送是异步的,非阻塞的

3.消息一旦发送成功,不能修改,类似于邮件的发送来往

4.Actor之间传递时,自己决定决定去检查消息,而不是一直等待,是异步非阻塞的

 

 

 

 

posted @ 2020-07-30 15:44  龘人上天  阅读(127)  评论(0编辑  收藏  举报