Scala快速入门

本文概述了Scala语言的六大特征、数据类型、常量和变量、类与对象、条件判断与循环,深入解析函数式编程特性如普通函数、递归、高阶函数等。此外,还介绍了字符串处理、集合操作、元组、trait、模式匹配及并发编程中的Actor模型。
摘要由CSDN通过智能技术生成

目录

 

1.Scala六大特征

2.Scala数据类型

3.常量和变量

4.类和对象

5.条件判断

6.循环

6.1to和until

6.2for

6.3while和do while

7.函数

7.1普通函数

7.2递归函数

7.3参数默认值函数

7.4可变参数个数的函数

7.5匿名函数

7.6嵌套函数

7.7 偏应用函数

7.8高阶函数

7.9柯里化函数

8.字符串

8.1String

8.2StringBuilder

9.数组

10.集合

10.1 Seq

10.1.1 List

10.1.2 ListBuffer

10.2 Set

10.3 Map

11 元组

12 Trait

13 模式匹配

14 并发编程Actor

15 隐式转换

15.1 隐式值

15.2 隐式视图

15.3 隐式类


1.Scala六大特征

  1. Java和scala可以无缝混编,都是运行在JVM上的;
  2. 类型推测,不用指定类型;
  3. 并发和分布式(Actor,类似java多线程Thread);
  4. 特征trait,类似java的interface和abstract结合;
  5. 模式匹配,match case,类似java的switch case;
  6. 函数式编程,类似C的函数;

2.Scala数据类型

 

  • Scala所有类型都是类,Scala中Any是顶级父类,就是任意类型;
  • Any下面两个体系 值类型(AnyVal)和引用类型(AnyRef);
  • 把数值类型(Int Boolean char..)这一些归为值类型(AnyVal);
  • 把String和数组,列表等归为引用类型(AnyRef);
  • Null是一个类,在Java和Scala中小写的null是一个值,大写的Null是一个类,不允许再被继承,是一个终止的特征,继承了引用类型(AnyRef);
  • Nothing是所有类型的子类,没有实例对象
  • Unit代表的是一个值类型,类似void。

3.常量和变量

 

  • var声明变量,可修改;
  • val声明常量,一次赋值,不可修改;
  • var和val后都可不必指定数据类型,scala自行类型推断。

4.类和对象

  • class:成员变量都是非static,可创建多个对象,没有main方法(main是static);
  • object:成员变量都是static,单例模式;
  • case:样例类,类似java的entity,默认实现了toString、equals、copy和hashCode等方法。创建对象时可以用new,也可以不用;
object caseClassTest {
  def main(args: Array[String]): Unit = {
    val s1 = Student(1,1)
    val s2 = new Student(1,1)

    println(s1.toString)
    println(s1.equals(s2))
  }
}
//样例类Student
case class Student(id:Int, age:Int)
  • apply方法:class和object都可以定义apply方法,apply方法本质上来说就是可以直接用类名()或对象名()来直接调用的方法。
class Person {
  var name = "zs"
  var age = 10

  def apply() = {
    println("class person apply")
  }
}

object Person {
  def apply() = {
    println("object person apply")
    new Person()
  }
}

object Test {
  def main(args: Array[String]): Unit = {
    //调用object person apply
    val person = Person()
    //调用class person apply
    person()
  }
}

5.条件判断

与java一致。

6.循环

6.1to和until

/**
  * to和until
  * 例:
  * 1 to 10 返回1到10的Range数组,包含10
  * 1 until 10 返回1到10 Range数组 ,不包含10
  */
println(1 to 10)//打印 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
println(1 to (10,2))//步长为2,从1开始打印 ,1,3,5,7,9
println(1 until 10) //不包含最后一个数,打印 1,2,3,4,5,6,7,8,9
println(1 until (10,3))//步长为3,从1开始打印,打印1,4,7

6.2for

//可以分号隔开,写入多个list赋值的变量,构成多层for循环
//可以在for循环中加入条件判断
for(i <- 1 to 10; j <- 1 until 10;if (i%2) == 0){
  println("i="+ i +",j="+j)
}

/*
 *  yield 关键字
 *  1-100集合中的偶数存储到另一个集合
 *  yield关键字能够将符合要求的元素自动封装到一个集合中
 */
val rest = for(i <- 1 to 100; if i%2 == 0) yield i     //此时rest就为选择出的i构成的一个集合
for(elem <- rest)
  println(elem)

6.3while和do while

与java一致。

7.函数

函数格式: def 函数名(参数):返回值 = {函数体}

7.1普通函数

//函数定义
def fun (a: Int , b: Int) : Unit = {
  println(a+b)
}
//调用方式
fun(1,1)

7.2递归函数

/**
  * 递归函数
  * 5的阶乘
  */
def fun2(n :Int) :Int= {  //必须写返回值类型
  if(n == 1)
    n
  else
    n * fun2(n-1)
}

println(fun2(5))

7.3参数默认值函数

/**
  * 包含参数默认值的函数
  *  1. 函数的参数有默认值,在调函数的时候可以传参,也可以不传参,
  *  2. 若不传参使用的默认值,
  *  3. 如果传参,默认值会被覆盖
  */
def fun2(num1:Int = 10,num2:Int = 20) = {
  num1 + num2
}
//调用函数
fun2()

7.4可变参数个数的函数

参数中加*,表示参数个数可变,函数参数可以是一个也可以是多个,随机灵活的。

def fun5(args:Double*) = {
  /**
    *     在scala中
    *   +=前后的数值类型必须一致
    *   +前后的数值类型可以不一致
    */
  var sum = 0.0
  for(arg <- args){
    sum += arg
  }
  sum
}

println(fun5(1.8,2.2,3.3))

7.5匿名函数

格式为:val 函数名 = (参数) => {函数体}

/**
  * 匿名函数
  * 1.有参数匿名函数
  * 2.无参数匿名函数
  * 3.有返回值的匿名函数
  * 注意:
  * 可以将匿名函数返回给定义的一个变量
  * 匿名函数不能显式声明函数的返回类型
  */
//有参数匿名函数
val value1 = (a : Int) => {
  println(a)
}

//无参数匿名函数
val value2 = ()=>{
  println("我爱Angelababy")
}

//有返回值的匿名函数
val value3 = (a:Int,b:Int) =>{
  a+b
}

value1(1)
value2()
println(value3(4,4))

7.6嵌套函数

/**
  * 嵌套函数:在函数体内又定义了一个函数
  */
def fun7(n:Int)={
  def fun8(a:Int,b:Int):Int={
    a + b
  }
  fun8(n,1)
}

println(fun7(10))

7.7 偏应用函数

当多次调用某个函数,且函数的某个参数一直不变时,可以定义偏应用,写死不变的参数,只填写变化的参数。

//定义正常函数
def log(date :Date, s :String)= {
  println("date is "+ date +",log is "+ s)
}

以下为main中调用部分:
//出现多次调用函数,且第一个参数不变的情况
val date = new Date()
log(date ,"log1")
log(date ,"log2")
log(date ,"log3")

//定义偏应用函数logWithDate,写死第1个参数,只要传入第2个参数
//下划线相当于占位符的作用,手动传入即可
val logWithDate = log(date,_:String)
logWithDate("log11")
logWithDate("log22")
logWithDate("log33")

7.8高阶函数

函数的参数或返回值是函数。

//以下函数有2个参数,参数1是函数,参数2是Int数值
def hightFun(f:(Int,Int) => Int, a:Int) : Int = {
  f(a,100)
}

//作为参数的函数定义
def f(v1 :Int,v2: Int):Int  = {
  v1+v2
}

//函数调用
hightFun(f, 1)

7.9柯里化函数

不懂

8.字符串

8.1String

创建不可变字符串对象,使用与java类似,如下所示:

val s1 = " Abc "
val s2 = "abc"
//equals判断两个值是否相同
println(s1.equals(s2))
//equalsIgnoreCase判断两个值是否相同,忽略大小写
println(s1.equalsIgnoreCase(s2))
//trim去掉前后空格
println(s1.trim)
//indexOf字符串中与传入的assci码相同的值的下标
println(s1.indexOf("b"))

8.2StringBuilder

创建可变字符串对象,使用也是与java类似。

val s = new StringBuilder();
//append用于附加信息
s.append("abc")
//+同样也可附加信息
s += 'd'
println(s)

9.数组

关键字Array。

  • 一维数组
/**
  * Array关键词 创建一个长度为10 的Int类型的数组
  * 如果创建了一个Int类型的数组,那么初始值都是0
  * String类型的数组,初始是null
  * Boolean类型的数组,初始是false
  */
val nums = new Array[Int](10)
for(i <- 0 until nums.length){
  nums(i) = i * i
}
nums.foreach {println}
  • 二维数组

暂时不管。

10.集合

Scala的集合类如下:

Seq、Set、Map都继承自Iterable。

10.1 Seq

Seq是元素可重复的集合。

Scala的Seq类似Java的List,是Trait类型的。

其子类大致分为两大类,索引序列和线性序列。

  • 索引序列意味着随机存取是最高效的,当创建一个IndexedSeq时,默认会创建一个Vector的列表。
scala> val x = IndexedSeq(1,2,3)
x: IndexedSeq[Int] = Vector(1, 2, 3)
  • 线性序列说明集合可以很方便的被分辨为头尾部分,并且用head、tail和isEmpty方法是很常见的。当创建一个LinearSeq时会创建一个list的列表。
scala> val seq = scala.collection.immutable.LinearSeq(1,2,3)
seq: scala.collection.immutable.LinearSeq[Int] = List(1, 2, 3)

10.1.1 List

 

val list1 = List(1,2,3,4,5)
//contains判断是否存在参数值的元素
println(list1.contains(6))
//drop丢弃前面n个元素
list1.drop(2).foreach { print }
println()
//take获取前面n个元素
list1.take(3).foreach(print)
println()
//map用于List元素一一映射
list1.map {x=> x +","}.foreach(x=>print(x))
list1.map {_ +","}.foreach(x=>print(x))
println()
//exists判断是否存在符合条件的元素
println(list1.exists { x => x > 300 })

val list2 = List("hello world", "ni hao")
//flatmap用于List元素扁平化映射
//_可以替换x=>x,其中_的位置与第二个x相同
list2.flatMap(x=>x.split(" ")).foreach(x=>println(x))
list2.flatMap(_.split(" ")).foreach(println(_))

10.1.2 ListBuffer

val listBuffer = new ListBuffer[String]
listBuffer += ("hello")
listBuffer += ("bj")
listBuffer.foreach { print }
println

listBuffer -= ("hello")
listBuffer.foreach { print }

10.2 Set

Set集合是元素不可重复的集合。

//创建Set
val set1 = Set(1,2,3,4,4)
val set2 = Set(1,2,3)

//遍历(Set会自动去重)
//方式一:foreach
set1.foreach(println)
//方式二:for
for(s<-set1) {
  println(s)
}

//常用方法
//交集
set1.intersect(set2).foreach(print)
println()
set1.&(set2).foreach(print)
println()
//判断是否是子集
println(set1.subsetOf(set2))
println()
//差集
set1.diff(set2).foreach(print)
println()
set1.&~(set2).foreach(print(_))
println()
//最大值
println(set1.max)
//最小值
println(set1.min)
//转成数组
set1.toArray.foreach(print)
println()
//转成List
set1.toList.foreach(print)
println()
//转成字符串mkString
println(set1.mkString(" "))

10.3 Map

Map是key-value格式的集合。

val map = Map(
  "name" -> "houpk",
  "age" -> 35,
  "sex" -> "male"
)

//根据key获取value
println(map("name"))

//遍历
//方式一
val keys = map.keys
val iterator = keys.iterator
while (iterator.hasNext) {
  val key = iterator.next()
  println(map(key))
}
//方式二
for (k<-map) {
  println(k._1+","+k._2)
}

/*
Map中的方法 :
1. filter:过滤,留下符合条件的记录
2. count:统计符合条件的记录数
3. contains:map中是否包含某个key
4. exist:符合条件的记录存在不存在
*/
map.filter(x=>x._1.equals("name")).foreach(println)
println(map.count(_._1.equals("name")))
println(map.contains("name"))
println(map.exists(_._1.equals("name")))

11 元组

元组类似数据库的表,元组中的元素就是表的字段。关键字为Tuple,使用小括号封装。

//创建元组
val t2 = Tuple2(1, "hello")
val tt2 = (1,"hello")

val t3 = Tuple3(1,2,"hello")
val tt3 = (1,2,"hello")

//元组遍历
val tupleIterator = tt3.productIterator
while (tupleIterator.hasNext) {
  println(tupleIterator.next())
}

//swap用于tuple2元素交换位置
val swap2 = t2.swap
println(swap2._1 + "," + swap2._2)

12 Trait

  • Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。与接口不同的是,它还可以定义属性和方法的实现。是抽象类和接口的结合。
  • 一般情况下Scala的类可以继承多个Trait,从结果来看就是实现了多重继承
  • Trait的继承用extends关键字继承,多继承时多个Trait之间用with连接。
  • Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait。
  • 继承的多个trait中如果有同名的方法和属性,必须要在类中使用“override”重新定义。
  • trait中不可以传参数。
trait Read {
  val readType = "read"
  val gender = "m"

  def read(name:String): Unit = {
    println("i am read " + name)
  }
}

trait Listen {
  val listenType = "Listen"
  val gender = "m"

  def listen(name:String): Unit = {
    println("i am listen " + name)
  }
}

class Person() extends Read with Listen {
  override val gender = "n"
}

object test{
  def main(args: Array[String]): Unit = {
    val person = new Person()
    person.read("abc")
    person.listen("def")
    println(person.gender)
  }
}

13 模式匹配

  • 类似java的switch case;
  • Scala除了匹配值,还可以匹配类型,类型的匹配必须要有变量名;
  • 匹配项使用关键字case;
  • 匹配项后跟表达式,使用=>隔开匹配项和表达式;
  • 表达式不需要break,会自动break
def main(args: Array[String]): Unit = {
  val tuple = (1,2,3f,"4",5d)
  val iterator = tuple.productIterator
  while (iterator.hasNext) {
    matchTest(iterator.next())
  }
}

def matchTest(x:Any) = {
  x match {
    case 1 => println("x is 1")
    case x:Int => println("x type is Int")
    case _ => println("not match")
  }
}

14 并发编程Actor

https://www.cnblogs.com/yinzhengjie/p/9376296.html

Scala在2.11.x版本中将Akka加入其中,作为其默认的Actor。

Actor类似java的Thread,每个Actor将状态和行为封装在一个轻量的进程/线程中,不和其他Actor分享状态,当需要与其他Actor交互时,通过发送消息/事件实现。

Actor特征总结如下:

  1. Actor间通信是消息机制,每个Actor都有自己的消息队列,进来的消息按先来后到排列;
  2. 消息发送是异步的,非阻塞的;
  3. 消息一旦发送成功,不能修改;

首先在dependency中添加依赖:

<!-- 添加akka的actor依赖 -->
<dependency>
    <groupId>com.typesafe.akka</groupId>
    <artifactId>akka-actor_2.11</artifactId>
    <version>2.4.17</version>
</dependency>

<dependency>
    <groupId>com.typesafe.akka</groupId>
    <artifactId>akka-remote_2.11</artifactId>
    <version>2.4.17</version>
</dependency>

使用代码如下:

object ActorTest {
  def main(args: Array[String]): Unit = {
    //创建线程池对象MyFactory,用来创建actor的对象的
    val MyFactory = ActorSystem("ActorTest")
    //通过MyFactory.actorOf方法来创建一个actor,注意,Props方法的第一个参数需要传递我们自定义的HelloActor类,
    //第二个参数是给actor起个名字
    val p1 = MyFactory.actorOf(Props[Actor1], "player1")

    //给actor p1发送消息
    p1 ! "start"
    p1 ! "hello"
    p1 ! "stop"
  }
}

class Actor1 extends Actor {
  override def receive: Receive = {
    case "start" => {
      println("start")
    }

    case "stop" => {
      println("end")
      context.stop(self)
      context.system.terminate() // 关闭ActorSystem,即关闭其内部的线程池(ExcutorService)
    }

    case _ => {
      println("sorry,i cannot follow you")
    }
  }
}

15 隐式转换

隐式转换关键字implicit,在编写程序的时候可以尽量少的去编写代码,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量。

隐式转换分为三类:隐式值、隐式视图、隐式类。

15.1 隐式值

使用implicit修饰变量,当缺失变量造成编译出错时,默认使用这个变量。

//参数前使用implicit关键字
def sayName(implicit name:String): Unit = {
  println(name)
}

def main(args: Array[String]): Unit = {
  /* 将变量声明为implicit,编译器在执行sayName方法时发现缺少一个String类型的参数,此时会搜索作用域内类型为String的隐式值,并且将搜索到的隐式值作为sayName的参数值 */
  implicit var s = "Angelababy"
  sayName
}

15.2 隐式视图

使用implicit修饰方法,当编译出错时,默认会调用这个方法。

def main(args: Array[String]): Unit = {
  /* addNum参数是String,直接调用会报错,在编译的时候,发现作用域内
  有一个隐式方法,正好这个方法的参数是String 返回值是Int,此时
  调用隐式方法,返回一个Int值,再将Int传给addNum */
  implicit def string2Int(num:String) = Integer.parseInt(num)
  addNum("1000")
}

def addNum(num:Int): Unit = {
  num + 1000
}

15.3 隐式类

隐式类就是使用implicit修饰类,当编译出错时,默认转换为定义的隐式类。

隐式类必须被定义在类,伴生对象和包对象里;

其所带的构造参数有且只能有一个。

package com.moshi.test

object ImplicitTest {
  def main(args: Array[String]): Unit = {
    /**
      * "abc"这个字符串想要调用getLength,但是自己没有实现这个方法
      * 发现作用域内有一个隐式转换的类,类的构造函数的参数是String类型
      * "abc"传给构造函数,得到这个类的对象,从而调用getLength方法
      */
    import com.moshi.test.Util._
    "abc".getLength()
  }
}

object Util{
  //定义隐式类,构造函数的参数为String
  implicit class Int2String(s:String) {
    def getLength()= s.length
  }
}

 

https://blog.csdn.net/hjy1821/article/details/83751384


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值