关闭

Scala学习笔记

73人阅读 评论(0) 收藏 举报

基础

  • 函数是一等公民

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

val squareVal = (a: Int) => a * a

   

def addOne(f: Int => Int, arg: Int) = f(arg) + 1

   

println("squareVal(2):" squareVal(2))

println("addOne(squareVal,2):" + addOne(squareVal, 2))

   

// squareVal(2):4

// addOne(squareVal,2):5

/******************************************************/

import scala.reflect.io.File

import java.util.Scanner

def withScanner(f: File, op: Scanner => Unit) = {

    val scanner = new Scanner(f.bufferedReader)

    try {

        op(scanner)

    } finally {

        scanner.close()

    }

}

withScanner(File("/proc/self/stat"),

    scanner => println("pid is " + scanner.next()))

   

  

  • 按名称传递参数

1

2

3

4

5

6

7

8

9

   

  

val logEnable = false

   

def log(msg: => String) =          // 多了"=>"符号,按值传递变为按名称传递

    if (logEnable) println(msg)

   

val MSG = "programing is running"

   

log(MSG + 1 / 0)  //没有除零的异常,参数到用的时候才计算,所以异常被跳过了

  • 定义类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

class Persion(val firstName: String, val lastName: String) {

   

    private var _age = 0

    def age = _age

    def age_=(newAge: Int) = _age = newAge

   

    def fullName() = firstName + " " + lastName

   

    override def toString() = fullName()

}

   

val obama: Persion = new Persion("Barack", "Obama")

   

println("Persion: " + obama)

println("firstName: " + obama.firstName)

println("lastName: " + obama.lastName)

obama.age_=(51)

println("age: " + obama.age)

   

  

  • 鸭子类型

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

def withClose(closeAble: { def close(): Unit },

    op: { def close(): Unit } => Unit) { //使用{def close():Unit}作为参数,任何含有close()函数的类都可以作为参数

    try {

        op(closeAble) //第二个参数被调用,接着第一个参数被调用

    } finally {

        closeAble.close()

    }

}

   

class Connection {

    def close() = println("close Connection")

}

   

val conn: Connection = new Connection()

withClose(conn, conn =>

    println("do something with Connection"))

   

  

  • 柯里化

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

def withClose(closeAble: { def close(): Unit })

    (op: { def close(): Unit } => Unit) {

    try {

        op(closeAble)

    } finally {

        closeAble.close()

    }

}

   

class Connection {

    def close() = println("close Connection")

}

   

val conn: Connection = new Connection()

withClose(conn)(conn =>

    println("do something with Connection"))

   

/****************************************/

def add(x:Int, y:Int) = x + y      //普通函数

def add(x:Int) = (y:Int) => x + y  //柯里化的函数

def add(x:Int)(y:Int) = x + y      //简化的写法

   

  

  • 泛型

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

def withClose[A <: { def close(): Unit }, B](closeAble: A)

  (f: A => B): B =

  try {

    f(closeAble)

  } finally {

    closeAble.close()

  }

class Connection {

  def close() = println("close Connection")

}

val conn: Connection = new Connection()

val msg = withClose(conn) { conn =>

  {

    println("do something with Connection")

    "123456"

    //123456

  }

}

   

println(msg)

   

  

  • Traits

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

trait ForEachAble[A] {

  def iterator: java.util.Iterator[A]

  def foreach(f: A => Unit) = {

    val iter = iterator

    while (iter.hasNext)

      f(iter.next)

  }

}

   

trait JsonAble {

  def toJson() =

    scala.util.parsing.json.JSONFormat.defaultFormatter(this)

}

// 使用with关键字混入foreachtoJson的功能

val list = new java.util.ArrayList[Int]() with ForEachAble[Int] with JsonAble

list.add(1); list.add(2)

   

println("For each: "); list.foreach(x => println(x))

println("Json: " + list.toJson())

   

  

函数式

  • 模式匹配

1

2

3

4

5

6

7

8

9

10

def fibonacci(in: Any): Int = in match {

    case 0 => 0

    case 1 => 1

    case n: Int if(n>1) => fibonacci(n - 1) + fibonacci(n - 2)  // if语句排除负数

    case n: String => fibonacci(n.toInt)  //匹配String类型

    case _ => 0   //匹配所有情况

}

println(fibonacci(3))

println(fibonacci(-3))

println(fibonacci("3"))

   

  

  • Case Class

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

abstract class Expr

   

case class FibonacciExpr(n: Int) extends Expr {

  require(n >= 0)

}

   

case class SumExpr(a: Expr, b: Expr) extends Expr

   

def value(in: Expr): Int = in match {

  case FibonacciExpr(0) => 0

  case FibonacciExpr(1) => 1

  case FibonacciExpr(n) =>

    value(SumExpr(FibonacciExpr(n - 1), FibonacciExpr(n - 2)))

  case SumExpr(a, b) => value(a) + value(b)

  case _ => 0

}

println(value(FibonacciExpr(3)))

   

  

  • 函数式例子

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

   

  

val list = List(1, 2, 3, 4)

   

def containsOdd(list: List[Int]): Boolean = {

  for (i <- list) {

    if (i % 2 == 1)

      return true;

  }

  return false;

}

println("list contains Odd ? " + containsOdd(list))

println("list contains Odd ? " + list.exists((x:Int) => x%2==1))

println("list contains Odd ? " + list.exists(_%2 == 1))

   

/*********************************************************/

val file = List("warn 2013 msg", "warn 2012 msg",

  "error 2013 msg", "warn 2013 msg")

   

println("cat file | grep 'warn' | grep '2013' | wc : "

    + file.filter(_.contains("warn")).filter(_.contains("2013")).size)

   

/******************map and reduce******************************/

val file = List("warn 2013 msg", "warn 2012 msg",

  "error 2013 msg", "warn 2013 msg")

   

def wordcount(str: String): Int = str.split(" ").count("msg" == _)

     

val num = file.map(wordcount).reduceLeft(_ + _)

   

println("wordcount:" + num)

  • 尾递归

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

val file = List("warn 2013 msg", "warn 2012 msg",

  "error 2013 msg", "warn 2013 msg")

   

def wordcount(str: String): Int = str.split(" ").count("msg" == _)

   

def foldLeft(list: List[Int])(init: Int)(f: (Int, Int) => Int): Int = {

  list match {

    case List() => init

    case head :: tail => foldLeft(tail)(f(init, head))(f)

  }

}

   

val num = foldLeft(file.map(wordcount))(0)(_ + _)

   

println("wordcount:" + num)

//wordcount:4

   

  

  • 更强大的for循环

1

2

3

4

5

6

7

8

9

10

11

12

13

val file = List("warn 2013 msg", "warn 2012 msg",

  "error 2013 msg", "warn 2013 msg")

   

def wordcount(str: String): Int = str.split(" ").count("msg" == _)

   

val counts =

  for (line <- file)

    yield wordcount(line)

   

val num = counts.reduceLeft(_ + _)

   

println("wordcount:" + num)

//wordcount:4

   

  

  • Option

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

def getProperty(name: String): Option[String] = {

  val value = System.getProperty(name)

  if (value != null) Some(value) else None

}

   

val osName = getProperty("os.name")

   

osName match {

  case Some(value) => println(value)

  case _ => println("none")

}

//Linux

   

println(osName.getOrElse("none"))

//Linux

   

osName.foreach(print _)

//Linux

   

  

  • Lazy初始化

1

2

3

4

5

6

7

8

9

10

11

12

13

14

class ScalaCurrentVersion(val url: String) {

  lazy val source= {

    println("fetching from url...")

    scala.io.Source.fromURL(url).getLines().toList

  }

  lazy val majorVersion = source.find(_.contains("version.major"))

  lazy val minorVersion = source.find(_.contains("version.minor"))

}

   

val version = new ScalaCurrentVersion(

  "https://raw.github.com/scala/scala/master/build.number")

println("get scala version from " + version.url)

version.majorVersion.foreach(println _)

version.minorVersion.foreach(println _)

   

  

并发

  • 使用Actor

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

import akka.actor.{ Actor, ActorSystem, Props }

   

val system = ActorSystem()  //开始

   

class EchoServer extends Actor {  //继承

  def receive = {           //接受消息

    case msg: String => println("echo " + msg)

  }

}

   

val echoServer = system.actorOf(Props[EchoServer])     //创建

echoServer ! "hi"       //发送

   

system.shutdown    //结束

   

/************************Actor更简化的用法********************************/

import akka.actor.ActorDSL._

import akka.actor.ActorSystem

   

implicit val system = ActorSystem()

   

val echoServer = actor(new Act {

  become {

    case msg => println("echo " + msg)

  }

})

echoServer ! "hi"

system.shutdown

   

  

  • Actor原理

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

import akka.actor.{ Actor, Props, ActorSystem }

import akka.testkit.CallingThreadDispatcher

   

implicit val system = ActorSystem()

   

class EchoServer(name: String) extends Actor {

  def receive = {

    case msg => println("server" + name + " echo " + msg +

      " by " + Thread.currentThread().getName())

  }

}

   

val echoServers = (1 to 10).map(x =>

  system.actorOf(Props(new EchoServer(x.toString))

    .withDispatcher(CallingThreadDispatcher.Id)))

(1 to 10).foreach(msg =>

  echoServers(scala.util.Random.nextInt(10)) ! msg.toString)

   

system.shutdown

Actor比线程轻量。在Scala中可以创建数以百万级的Actor。奥秘在于Actor直接可以复用线程。

Actor和线程是不同的抽象,他们的对应关系是由Dispatcher决定的。

这个例子创建4个Actor,每次调用的时候打印自身线程名称。

可以发现Actor和线程之间没有一对一的对应关系。一个Actor可以使用多个线程,一个线程也会被多个Actor复用。

   

   

  • 同步返回

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

import akka.actor.ActorDSL._

import akka.pattern.ask

   

implicit val ec = scala.concurrent.ExecutionContext.Implicits.global

implicit val system = akka.actor.ActorSystem()

   

val versionUrl = "https://raw.github.com/scala/scala/master/starr.number"

   

val fromURL = actor(new Act {

  become {

    case url: String => sender ! scala.io.Source.fromURL(url)

      .getLines().mkString("\n")

  }

})

   

val version = fromURL.ask(versionUrl)(akka.util.Timeout(5 * 1000))

version.foreach(println _)

     

system.shutdown

Actor非常适合于较耗时的操作。比如获取网络资源。

这个例子通过调用ask函数来获取一个Future。

在Actor内部通过 sender ! 传递结果。

Future像Option一样有很多高阶方法,可以使用foreach查看结果。

   

   

  • 异步返回

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

import akka.actor.ActorDSL._

import akka.pattern.ask

   

implicit val ec = scala.concurrent.ExecutionContext.Implicits.global

implicit val system = akka.actor.ActorSystem()

   

val versionUrl = "https://raw.github.com/scala/scala/master/starr.number"

   

val fromURL = actor(new Act {

  become {

    case url: String => sender ! scala.io.Source.fromURL(url)

      .getLines().mkString("\n")

  }

})

   

val version = fromURL.ask(versionUrl)(akka.util.Timeout(5 * 1000))

version onComplete {

  case msg => println(msg); system.shutdown

}

异步操作可以最大发挥效能。Scala的Futrue很强大,可以异步返回。

可以实现Futrue的onComplete方法。当Futrue结束的时候就会回调。

在调用ask的时候,可以设定超时。

   

   

  • 并行集合

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

val urls = List("http://scala-lang.org",

  "https://github.com/yankay/scala-tour")

   

def fromURL(url: String) = scala.io.Source.fromURL(url)

  .getLines().mkString("\n")

   

val t = System.currentTimeMillis()

//urls.map(fromURL(_))

urls.par.map(fromURL(_))   //并发执行

println("time: " + (System.currentTimeMillis - t) + "ms")

   

/********************************************************/

val file = List("warn 2013 msg", "warn 2012 msg",

  "error 2013 msg", "warn 2013 msg")

   

def wordcount(str: String): Int = str.split(" ").count("msg" == _)

   

val num = file.par.map(wordcount).par.reduceLeft(_ + _)  // 并发执行

   

println("wordcount:" + num)

   

  

  • 远程Actor

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

import akka.actor.{ Actor, ActorSystem, Props }

import com.typesafe.config.ConfigFactory

   

implicit val system = akka.actor.ActorSystem("RemoteSystem",

  ConfigFactory.load.getConfig("remote"))

class EchoServer extends Actor {

  def receive = {

    case msg: String => println("echo " + msg)

  }

}

   

val server = system.actorOf(Props[EchoServer], name = "echoServer")

   

val echoClient = system

  .actorFor("akka://RemoteSystem@127.0.0.1:2552/user/echoServer")

echoClient ! "Hi Remote"

   

system.shutdown

Actor是并发模型,也使用于分布式。

这个例子创建一个Echo服务器,通过actorOf来注册自己。

然后再创建一个client,通过akka url来寻址。

除了是通过url创建的,其他使用的方法和普通Actor一样。

   

   

实践

  • 使用Java

1

2

3

4

5

6

7

8

import org.apache.commons.beanutils.BeanUtils

import scala.beans.BeanProperty

   

//@BeanProperty注解来生成Java StyleBean

class SimpleBean(@BeanProperty var name: String) {

}

val bean = new SimpleBean("foo")

println(BeanUtils.describe(bean))

   

  

  • 相等性

1

2

3

4

5

6

7

8

9

10

11

12

class Person(val name: String) {

  override def equals(other: Any) = other match {

    case that: Person => name.equals(that.name)

    case _ => false

  }

}

   

case class Test(val name:String, val age:Int){  // case类自动生成正确的equals方法

}

   

println(new Person("Black") == new Person("Black"))

println(new Test("Black",12) == new Test("Black",12))

   

  

  • 抽取器

1

2

3

4

5

6

7

8

9

10

11

12

13

import scala.util.matching.Regex

   

object Email {

  def unapply(str: String) = new Regex("""(.*)@(.*)""")

    .unapplySeq(str).get match {

    case user :: domain :: Nil => Some(user, domain)

    case _ => None

  }

}

   

"user@domain.com" match {

  case Email(user, domain) => println(user + "@" + domain)

}

抽取器可以帮助模式匹配进行解构。

Scala的正则表达式会自带抽取器,可以抽取出一个List。List里的元素是匹配()里的表达式。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:3488次
    • 积分:209
    • 等级:
    • 排名:千里之外
    • 原创:18篇
    • 转载:0篇
    • 译文:0篇
    • 评论:2条
    文章分类
    最新评论