Scala 自学笔记[转]
快学Scala自学笔记
第一至第四章
参考
http://blog.csdn.net/escaflone/article/details/43485345
1、变量声明
val answer = 8 * 5 + 2; //常量 var counter = 0; //变量 //在必要的时候 ,可以指定类型 val greeting:String = null val greeting:Any = "Hello" //可以将多个值或变量放在一起声明 val xmax, ymax = 100 //xmax 和 ymax设为100 var greeting, message:String = null // 都被设为字符串,被初始化为null
常用类型:
常用数值类型 Byte Char Short Int Long Float Double Boolean BigInteger BigDecimal 用于任意大小的数字
scala的StringOps,RichInt,RichDouble,RichChart给基本类型提供了很多方法,在调用时会自动隐式转换
"Hello".intersect("World") //输出"lo" 输出两个字符串共通的一组字符 1.to(10) //Int值1首先被转换为RichInt,然后调用to方法
类型转换用方法
不像java用 强制类型转换,而是用方法 99.44.toInt //99, 这里不带参数,并且不改变当前对象的方法 通常不实用圆括号 99.toChart //'c' 99.toString //"99" "99.44".toDouble // 99.44
apply方法类似函数调用的语法
"Hello"(4) // '0' 实际上是StringOps类的apply方法 def apply(n:Int) : Char "Hello".apply(4) // 完整写法 BigInt伴生对象的apply方法: BigInt("1234567890") // BigInt.apply("1234567890") BigInt("123") * BigInt("123") 数组Array,也是伴生对象 Array(1,4,9,16)
2、控制结构和函数
if (x > 0) 1 else -1 可以将if/else表达式的值赋给变量 val s = if(x > 0) 1 else -1 每个表达式都有一个类型 if(x > 0) 1 else -1 // Int if(x > 0) "p" else -1 // Any (Int 和String的超类) if(x > 0) 1 // (),Unit类,因为可能没有输出值,即if(x >0) 1 else () while(n > 0){ r = r*n n -=1 }
for循环
for( i <- 表达式) for( i <- 1 to 10) r = r*i val s = "Hello" var sum = 0 for( i <- 0 until s.length) sum+= s(i) 简化版: //这个没看懂 var sum = 0 for(ch <- "Hello") sum+=ch
高级for循环和for推导式
for( i <- 1 to 3; j <- 1 to 3) println((10 * i + j)+ "") 11 12 13 21 22 23 31 32 33 for(i <- 1 to 3; j <- 1 to 3 if i != j)print((10 * i + j)+ "") 12 13 21 23 31 32 注意在if前没有分号 from是在循环中使用的变量 for(i <- 3; from = 4 - i ; j <- from to 3) print((10 * i + j) + " ") 31 22 23 31 32 33 以yield开始,则循环会构造出一个集合,每次迭代生成集合中的一个值 for( i <- 1 to 10) yield i % 3 生成 Vector(1,2,0,1,2,0,1,2,0,1) 推导式生成的集合与第一个生成器是类型兼容的: for( c<- "Hello"; i<- 0 to 1) yield (c + i).toChar "Hilflmlmop" for(i <- 0 to 1; c <- "Hello") yield (c + i).toChar Vector('H','e','l',''l','o','I','f','m','m','p')
函数
def abs(x:Double) = if(x >=0) x else -x def fac(n:Int) = { var r=1 for( i<- 1 to n) r=r*i r // 无需return,最后一行即返回值 } 一般定义函数无需指定返回类型,Scala可以通过=符号右侧的表示式的类型推断返回类型,除非是递归函数。 对于递归函数,必须指定返回类型 def fac(n:Int) :Int = if(n<=0) 1 else n* fac(n-1)// 如果没有返回类型,Scala无法校验 n*fac(n-1)的类型是Int
默认参数和带名参数
//left默认值"[" def decorate(str:String, left:String="[", right:String ="]") = left + str +right decorate("Hello", "<<<", ">>>") // <<<Hello>>> decorate("Hello","<<<") // <<<Hello] decorate(left = "<<<", str = "Hello" , right = ">>>") // 指定参数名,<<<Hello>>> decorate("Hello", right="]<<<") // 混用<<<Hello]<<<
变长参数
实现一个可以接受可变长度参数列表的函数会更方便。 def sum(args: Int*){ var result = 0 for (arg <- args) result += arg result } val s = sum(1,4,9,16,25) //函数得到 类型Seq的参数 Seq类型可以用for循环来访问每一个元素 val s = sum(1 to 5) // 错误 val s = sum(1 to 5: _*) //将 1 to 5当做参数序列处理 递归中使用 def recursiveSum(args : Int *): Int = { if (args.length ==0) 0 else args.head + recursiveSum(args.tail:_*) // head是首个元素, tail是所有其他元素的序列,是一个Seq }
过程
过程不返回任何值,可以略去=号 def box(x:String) { println(x) } 也可以显式声明Unit返回类型 def box(x:String) :Unit = {}</span>
懒值
lazy val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString //直到我们首次对它取值才会初始化。 可以把懒值当做介于 val和def的中间状态: val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString//在words被定义时即被取值 lazy val words= scala.io.Source.fromFile("/usr/share/dict/words").mkString//在首次调用 def words= scala.io.Source.fromFile("/usr/share/dict/words").mkString//在每一次被使用时
异常
if (x >= 0 ) { sqrt(x) } else throw new IllegalArgumentException("x should not be negative") throw 表达式有特殊的类型Nothing, 在if/else中,如果以个分支的类型为Nothing, 那么表达式的类型就是 另一个分支的类型, 在这里就是 Double
捕获异常,使用模式匹配 try{ }catch{ case _: MalformedURLException => println("Bad Url:" + url) case ex: IOException => ex.printStackTrace() } var in = new URL("http://xxx.com").openStream() try{ process(in) }finally{ in.close() } try{...} catch{...} finally{...}
3、数组
定长数组 val nums = new Array[Int](10) // 都是0 val a = new Array[String](10) // 都是null val s = Array("Hello", "World") // Array伴生对象的apply 方法 s(0) = "Goodbye" //Array("Goodbye","World") 变长数组 import scala.collection.mutable.ArrayBuffer val b = ArrayBuffer[Int]() // 伴生对象的apply //或者 new ArrayBuffer[Int] b += 1 //(1) b += (1,2,3,5) // (1,1,2,3,5) b ++= Array(8,13,21) // 可以用++=追加任何集合 (1,1,2,3,5,8,13,21) b.trimEnd(5) //移除最后5个元素 , (1,1,2) b.insert(2,6) // (1,1,6,2) b.insert(2,7,8,9) // (1,1,7,8,9,6,2) b.remove(2) // (1,1,8,9,6,2) b.remove(2,3) //(1,1,2) b.toArray // Array(1,1,2) ,变长转定长 a.toBuffer // 定长转变长
遍历数组
for(i <- 0 until.a.length) println(i + ": " + a(i)) 如果在循环体中不需要数组下标,可以直接访问数组元素 for(elem <- a ) println(elem) elem先后被设为a(0),a(1),依此类推。
数组转换
for (...) yield 循环创建了一个类型与原始集合相同的新集合。 val a = Array(2,3,5,7,11) val result = for(elem <- a) yield 2 * elem //yield 有疑问? // result 是 Array(4, 6, 10 , 14, 22) 对每个偶数翻倍,并丢掉奇数元素 for(elem <- a if elem %2 ==0) yield 2 * elem 另一种做法 a.filter(_ % 2 ==2).map(2 * _) 移除第一个负数之外的所有负数 首先收集需要保留的下标: var first = true val indexs = for(i <-0 until a.length if first || a(i) >=0) yield { if(a(i)<0) first = false; i // 按书序记录了所有正数和第一个负数的小标,其他负数的小标都丢弃了 for(j <- 0 until.indexs.length) a(j) = a(index(j))//将元素移动到该去的位置 a.trimEnd(a.length - indexs.length)//并截断尾端//这里主要是 小标处理
常用算法
数组:Array(1,7,2,9).sum //19 数组缓冲:ArrayBuffer("Mary","had","a","little",'lamb').max //"little" val b = ArrayBuffer(1,7,2,9) val bSorted = b.sorted //b没有改变 bSorted是ArrayBuffer(1,2,7,9) 提供一个比较函数,用sortWith方法 val bSorted = b.sorted(_ < _)// (1,2,7,9) 这里b没有改变 直接对一个数组排序,单不能对数组缓冲排序 val a = Array(1,7,2,9) scala.util.Sorting.quickSort(a) // 此方法不适于ArrayBuffer 想要显示数组或数组缓冲的内容,可以用mkString a.mkString(" and ") // "1 and 2 and 7 and 9" a.mkString("<", "," , ">")// "<1,2,7,9>"
多维数组
通过数组的数组来实现: Array[Array[Double]] 也可以通过ofDim方法: val matrix = Array.ofDim[Double](3,4) // 三行,四列 要访问其中的元素,使用两对圆括号: matrix(row)(col) = 42 创建不规则的多维数组 var triangle = new Array[Array[Int]](10) for(i <- 0 until triangle.length) triangle(i) = new Array[Int](i+1)
与Java的互操作
通过引入scala.collection.JavaConversions里的隐式转换方法,可以自动包装成Java对象,如列表等。 import scala.collection.JavaConversions.bufferAsJavaList import scala.collection.mutable.ArrayBuffer val command = ArrayBuffer("ls", "-all" , "/home/clat") val pb = new ProcessBuilder(command) // Scala to Java, Scala缓冲数组被包装成一个实现了java.until.List接口的Java类的对象 反过来,把Java.until.List,自动转换成一个Buffer import scala.collection.JavaConversions.asScalaBuffer import scala.collection.mutable.Buffer val cmd :Buffer[String] = pb.command() // java to scala, 不能使用ArrayBuffer, 包装起来的对象仅能保证是个Buffer
4、映射和元素
val scores = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8 ) //不可变Map[String, Int] val scores = scala.collection.mutable.Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8 ) //可变Map[String, Int] val scores = new scala.collection.mutable.HashMap[String, Int] //定义一个空的Map,需要给出类型参数 Map 是对偶的集合(两个值构成的组), -> 操作符 用来创建对偶, "Alice" -> 10 产出的值是 ("Alice", 10) 所以也可以用下面的方法定义 Map: val scores = Map(("Alice",10),("Bob",3),("Cindy",8)) //只不过 -> 操作符 比 圆括号 更易读,更符合大家对Map的直观感觉。 获取Map中的值 使用()表示法来查找某个键对应的值 val bobScore = scores("Bob") // 类似java的 scores.get("Bob"), 如果不存在,则抛出异常 检查是否有某个制定的键,可以用contains方法 val bobsScore = if(scores.contains("Bob")) scores("Bob") else 0 // 可以用contains 来判断 val bobsScore = scores.getOrElse("Bob",0) //返回Bob键对应的值;否则,返回0 映射.get(键)这样的调用返回一个Option对象,要么是Some(键对应值),要么是None.
更新Map
可变的Map score("Bob") = 10 //更新 scores("Fred") = 7 //增加 scores += ("Bob" -> 10, "Fred"-> 7) scoers -= "Alice" 不可变Map, 假定当前scores是不可变 val new Scores = scores + ("Bob" -> 10, "Fred"-> 7) // 产生一个新的Map 或者 当 scores 是 var变量 var scores = ... scores = scores + ("Bob" -> 10, "Fred"-> 7) scores = scores - "Alice"
迭代Map
for( (k, v) <- Map) 处理 k 和 v scores.keySet //一个类似 Set("Bob", "Cindy", "Alice")这样的集合 for(v <- scores.values) prinltn(v) // 打印 10 8 7 10 for( (k, v) <- map) yield ( v, k ) //反转Map
排序Map
默认Scala给的是 哈希表, val scores = scala.collections.immutable.SortedMap("Alice" -> 10, "Fred" -> 7, "Bob" -> 3, "Cindy" -> 8) // 如果需要排序,需要用树形Map 在Scala(2.9)中,还没有可变的 树形Map,只能用java的TreeMap 如果想按插入顺序访问所有键,可以用LinkedHashMap val months = scala.collection.mutable.LinkedHashMap("Jan" ->1, ,"Feb" ->2, "Mar" ->3 , ...)
与Java的互操作
Java -> Scala 引入语句 import scala.collection.JavaConversions.mapAsScalaMap val scores: scala.collection.mutable.Map[String, Int] = new java.util.TreeMap[String,Int] import scala.collection.JavaConversions.propertiesAsScalaMap val props:scala.collection.Map[String,String] = System.getProperties() Scala -> Java import scala.collection.JavaConversions.mapAsJavaMap import java.awt.font.TextAttribute._ val attrs = Map(FAMILY -> "Serif" , SIZE -> 12) val font = new javal.awt.Font(attrs) //该方法预期一个Java Map ?有疑问
元组
Map是k/v对偶的集合,对偶是元组最简单的形态, 元组是不同类型的值的聚集。 val t = (1,3.14,"Fred") // Tuple3[Int, Double, java.lang.String] val second = t._2 // 元组位置从1开始,这里是 3.14 //t._2 可以写成 t _2, 中间变空格 使用模式匹配来获取元组的组元 此处有疑问? val (first, second, thrid) = t // first设为1, second 设为3.14, third设为 "Fred" 当不需要所有部件时,可以在不需要的位置上使用_: val (first, second, _) = t 元组用于函数需要范围不止一个值得情况,如StringOps的partition方法,返回包含满足和不满足某条件的字符: "New York".partition(_.isUpper) // ("NY" , "ew ork")
拉链操作
使用元组的原因之一是把多个值绑在一起,以便它们能够被一起处理,这通常可以用zip方法来完成。 val symbols = Array("<", "-", ">") val counts = Array(2, 10 , 2) val pairs = symbols.zip(counts) // 输出对偶的数组, Array(("<", 2), ("-", 10), (">", 2)) 然后这些对偶就可以被一起处理: for((s,n) <- pairs) Console.print(s * n)// 会打印 <<---------->> 用toMap方法可以将对偶的集合转换成Map keys.zip(values).toMap//keys是k集合, values是与之平行对应的v集合
-------------------------------
http://www.importnew.com/4307.html
Scala教程:高级类型
相关推荐
匆匆那些年 2020-10-15
TheBigBlue 2020-07-28
shenwenjie 2020-07-07
muhongdi 2020-07-07
waitwolf 2020-07-08
yunfenglee 2020-07-08
yunfenglee 2020-07-08
kekeromer 2020-07-08
匆匆那些年 2020-07-07
liqinglin0 2020-07-05
TheBigBlue 2020-07-05
kekeromer 2020-06-13
zhixingheyitian 2020-06-08
TheBigBlue 2020-06-06
liqinglin0 2020-06-01
liqinglin0 2020-06-01
yunfenglee 2020-05-30
MICKEYSTUDY 2020-05-28
muhongdi 2020-05-19