scala学习笔记

● scala中遍历数据结构

一、for循环

 a. 以符号 <- 提供生成器

eg: 

   (1)  //打印1、2、3

        for (i <- 1 to 3) {  

            println(i) 

        }

   (2)  //遍历数组,添加到动态数组中

        for(i <- 0 until data.length) {

            dataArray.append(data(i)(0))

        }

   (3) //遍历tables数组,t作为每次遍历的元素在每次遍历时值分别是 "Runoob", "Baidu", "Google"

       

   val browers = Array("Runoob", "Baidu", "Google")

        for (t <- browers) {

            if (free_browers.contains(t)) {

                browerArrayBuffer.append(t)

            }

         }

 b.提供多个生成器,并以分号分隔,if表达式作为控制守卫

eg:

    (1) for (i <- 1 to 3; j <-1 to 3 if i > j) {  

            println(s"i=$i, j=$j, i+j=${i + j}") 

         } 

         输出:   i=2, j=1, i+j=3

                   i=3, j=1, i+j=4

                   i=3, j=2, i+j=5

c.yield循环体

注:for循环中的 yield 会把当前的元素记下来,保存在集合中,循环结束后将返回该集合。Scala中for循环是有返回值的。如果被循环的是什么结构,返回就是什么,

,返回的变量的类型与循环表达式中的类型一致

eg:

    (1) for (i <- 1 to 5) yield i * 2

        输出:scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)

 

    (2)  val filesHere = Map("java" -> 22, "scala" -> 6, "spark" -> 5)

          val scalaFiles =for {  

            file <- filesHere  

            if file._1.startsWith("java")  

            if file._2 == 22

        } yield file

        println(scalaFiles)

 

       输出:Map("java" -> 22)
       注:循环次数为filesHere的size,file为每次遍历时的元素值     
       
二、 foreach和map方法遍历数据结构
  eg:
      object arrayTest extends App{
         var increase=(x:Int)=>x+1
         val someNumbers = List ( -11, -10, - 5, 0, 5, 10)
         var b = someNumbers.foreach(increase)
         println(b.getClass)
         var c = someNumbers.map(increase)
          println(c.getClass)
         c.foreach((x:Int)=>print(x+" "))
         c.map((x:Int)=>print(x+" "))
       }

         注:Scala中的集合对象都有foreach和map两个方法。两个方法的共同点在于:都是用于遍历集合对象,并对每一项执行指定的方法。而两者的差异在于:foreach无返回值(准确说返回void),map返回                集合对象。见如下代码及运行结果:b.getClass 得到的是void, 而c.getClass得到的是colletion 。再看代码的第9-11行,foreach和map的运行结果一致。结论就是:foreach 无法代替map. 而                            map方法却可以代替foreach。

         注: scala中对集合使用map操作,即对集合的每一个元素都执行=>后面的转换操作,得到新的集合

    eg: val arr2 = Array(1,2,3,4,5)    

          val ret = arr2.map(_ * 2)

          ret值为Array(2,4,6,8,10)   

 引申-- flatten、flatMap、fillter、zip等函数组合器的使用

 

        注: flatten可以把嵌套的结构展开. 

   eg: scala> List(List(1,2),List(3,4)).flatten

         res0: List[Int] = List(1, 2, 3, 4)

 

         注:flatMap是map的一种扩展,可以认为是flatten和map的结合,在flatMap中,我们会传入一个函数,该函数对每个输入都会返回一个集合(而不是一个元素),然后,flatMap把生成的多个集合“拍扁”成为一个集合。

 

  eg: scala> val books = List("Hadoop","Hive","HDFS")

        books: List[String] = List(Hadoop, Hive, HDFS)

        scala> books flatMap (s => s.toList)

        res0: List[Char] = List(H, a, o, o, p, H, i, v, e, H, D, F, S)

 

        注:对象.方法在scala中可以写成 对象 空格  方法

 

       注:filter用于滤除掉使函数返回false的元素

 

   eg: scala> def isEven(i: Int): Boolean = i % 2 == 0

         isEven: (i: Int)Boolean

        scala> List(1,2,3,4).filter(isEven _)

        res6: List[Int] = List(2, 4)

 

    eg: //websocket根据用户向所有主题广播消息

         body.topic.foreach(it => topicMap = topicMap + (it -> body.user))

         topicMap.filter {

              ele => val (k, v) = ele

              v == s.user

         }.get(s.topic).map(_ => send(s))

 

            注: zip方法将两个集合结合在一起

      eg: scala>  List('a,'b,'c).zip(List(1,2,3))

            res32: List[(Symbol, Int)] = List(('a,1), ('b,2), ('c,3))

 

            注: zipWithIndex将元素和下标结合在一起

      eg: scala> List(2,3,4,5).zipWithIndex

            res33: List[(Int, Int)] = List((2,0), (3,1), (4,2), (5,3))

 

● scala的并发编程

一、 Future

        注:Future提供了一套高效便捷的非阻塞并行操作管理方案。其基本思想很简单,所谓Future,指的是一类占位符对象,用于指代某些尚未完成的计算的结果。一般来说,由Future指代的计算都是并行执                     行的,计算完毕后可另行获取相关计算结果。以这种方式组织并行任务,便可以写出高效、异步、非阻塞的并行代码。所谓Future,是一种用于指代某个尚未就绪的值的对象。而这个值,往往是某个                   计算过程的结果:

                (1)若该计算过程尚未完成,我们就说该Future未就位;

                (2)若该计算过程正常结束,或中途抛出异常,我们就说该Future已就位。

               Future的就位分为两种情况:

                (1)当Future带着某个值就位时,我们就说该Future携带计算结果成功就位。

                (2)当Future因对应计算过程抛出异常而就绪,我们就说这个Future因该异常而失败。

        注: Future的一个重要属性在于它只能被赋值一次。一旦给定了某个值或某个异常,future对象就变成了不可变对象——无法再被改写。

 

    a、创建Future

        创建future对象最简单的方法是调用future方法,该future方法启用异步(asynchronous)计算并返回保存有计算结果的futrue,一旦该future对象计算完成,其结果就变的可用。      

    eg: import scala.concurrent._
          import ExecutionContext.Implicits.global
          val session = socialNetwork.createSessionFor("user", credentials)
          val f: Future[List[Friend]] = Future {
              session.getFriends()
          }

         在上述例子中,然后我们初始化一个session变量来用作向服务器发送请求,用一个假想的 createSessionFor 方法来返回一个List[Friend]。为了获得朋友列表,我们必须通过网络发送一个请求,这个请求                能耗时很长。这能从调用getFriends方法得到解释。为了更好的利用CPU,响应到达前不应该阻塞(block)程序的其他部分执行,于是在计算中使用异步。future方法就是这样做的,它并行地执行指定的                计算块,在这个例子中是向服务器发送请求和等待响应。一旦服务器响应,future f 中的好友列表将变得可用

 

    b、 回调函数(Callbacks)

          Scala的Future提供了回调函数来获取它的结果,当Future完成后会自动调用onComplete,我们只需要根据它的结果再做处理即可,而其他互不依赖的操作可以继续执行不会阻塞

    eg: val fut = Future {
              Thread.sleep(1000)
              1 + 1
           }
           fut onComplete {
              case Success(r) => println(s"the result is ${r}")
              case _ => println("some Exception")
           }
           println("I am working")
            Thread.sleep(2000)
            

    c 、 组合器(combinators)

          //使用map操作从每个 future 中提取单一结果值,消除了所需的 match / case 结构

    eg:  val rateQuote = Future {

              connection.getCurrentValue(USD)

           }

           val purchase = rateQuote map { quote =>

                if (isProfitable(quote)) connection.buy(amount, quote)

                else throw new Exception("not profitable")

           }

           purchase onSuccess {

                  case _ => println("Purchased " + amount + " USD")

           }

二、 Actor

Scala中的Actor能够实现并行编程的强大功能,他是基于事件模板的并发机制。Actor是运用消息的发送接、收来实现多线程的。使用Scala能够更容易地实现多线程应用的开发,Actor是一种不共享数据,依赖于消息传递的一种并发编程模式,避免了死锁、资源争夺等情况。在具体实现的过程中,Scala中的Actor会不断的循环自己的邮箱,并通过receive偏函数进行消息的模式匹配并进行相应的处理如果Actor A和 Actor B要相互沟通的话,首先A要给B传递一个消息,B会有一个收件箱,然后B会不断的循环自己的收件箱, 若看见A发过来的消息,B就会解析A的消息并执行,处理完之后就有可能将处理的结果通过邮件的方式发送给A

 

a.创建actor

eg:

 

//继承Actor特质类

class HiActor extends Actor {

  //重写Actor特质类的抽象方法act,从而实现自己的业务逻辑

  override def act(): Unit = {

    //消息循环

    while (true)

    //使用case模式匹配接收到的消息

      receive {

        case "Hi" => println("Hello")

      }

  }

}

//也可以用调用ActorSystem.actorOf(..)的方法创建actor

 

b.启动actor

val newActor = new HiActor

newActor.start()

 

c.发送消息

eg:

import scala.actors.Actor

//样例类

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

//继承Actor特质类

class ActorTest extends Actor{

  override def act(): Unit = {

    while(true){

      receive{

        case Person(name,age)=>println(s"the name is ${name},the age is ${age}")

      }

    }

  }

}

 

object Actor2 {

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

    val act=new ActorTest()

    act.start()

    act ! Person("张三",18)

    act ! Person("李四",19)

    act ! Person("赵六",16)

  }

}

 

结果:

the name is 张三,the age is 18

the name is 李四,the age is 19

the name is 赵六,the age is 16

 

注:actor中!是发送消息异步执行,!?是同步执行。ask 函数就是 ?,意味着处理 message 的 actor (receiver) 需要把处理结果返回 sender。 tell 函数就是 !,不需返回

 

c. actor生命周期

actor是一个循环,actor在如下情形之一会终止执行:

(1)Act方法返回

(2)Act方法由于异常被终止(发送毒药信息)

(3)Actor调用exit方法

 

d. actor共享线程

某些程序包含的actor过多,以至于要为actor创建单独的线程开销会很大。此时需要考虑在同一个线程中运行多个actor。Actor有时大部分时间用户等待消息,这时actor所在的单独线程会堵塞,与其这样不如用一个线程来执行多个actor的消息处理函数。在Scala中,react方法可以实现这样的功能。react方法接收一个偏函数,并将它添加到邮箱,然后退出。

 

react工作原理

当你调用一个actor的start时,start方法会以某种方式来确保最终会有某个线程来调用那个actor的act方法。如果act方法调用了react ,则react方法会在actor的邮箱中查找传递给偏函数的能够处理的消息 。(和receive方法一样,传递待处理消息给偏函数的isDefinedAt方法。) 如果找到一个可以处理的消息,react 会安排一个在未来某个时间处理该消息的计划并抛出异常。如果它没有找到这样的消息,它会将actor置于“冷存储” 状态 ,在它通过邮箱收到更多消息时重新激活,并抛出异常。不论是哪种情况,react都会以这个异常的方式完成其执行,act 方法也随之结束  调用act的线程会捕获这个异常,忘掉这个actor , 并继续处理其他事务。这就是为什么你想要react在处理第一个消息之外做更多的事,你将需要在偏函数中再次调用act方法 ,或使用某种其他的手段来让react再次被调用。

eg:

import scala.actors.Actor

/**

  * scala Actor构建在java的线程基础之上的,

  * 为了避免频繁的线程创建、销毁和切换等,scala中提供了react方法

  * 方法执行完毕后,仍然被保留

  */

//样例类

case class Persion(val name:String,val age:Int)

case class Animal(val name:String,val age:Int)

 

class MyReact extends Actor{

  override def act(): Unit = {

    loop{

      react{

        case Person(name,age)=>{

          println(s"这是个人the name is ${name},the age is ${age}")

          Thread.sleep(2000)

          println(s"${name}会敲代码")

        }

        case Animal(name,age)=>{

          println(s"这是动物the name is ${name},the age is ${age}")

          Thread.sleep(2000)

          println(s"${name}会摇尾巴")

        }

        case _ =>println("不清楚是啥")

      }

 

    }

  }

}

object reactTest{

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

    val reac=new MyReact()

    reac.start()

    reac ! Person("蔡文姬",18)

    reac ! Animal("梦奇",16)

    println("完毕!")

  }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值