scala 构造函数 多个什么时候运行辅助构造器

Scala集合 - ImportNew
| 分类: ,
| 标签: ,
这个章节的内容包含
基本数据结构
函数组合器
基本数据结构
Scala提供了一些很方便的集合类。
参考 《Effective Scala》中关于怎么使用的内容。
scala& val numbers = List(1, 2, 3, 4)
numbers: List[Int] = List(1, 2, 3, 4)
集合中没有重复元素
scala& Set(1, 1, 2)
res0: scala.collection.immutable.Set[Int] = Set(1, 2)
元组(Tuple)
元组可以直接把一些具有简单逻辑关系的一组数据组合在一起,并且不需要额外的类。
scala& val hostPort = (&localhost&, 80)
hostPort: (String, Int) = (localhost, 80)
和case class不同,元组的元素不能通过名称进行访问,不过它们可以通过基于它们位置的名称进行访问,这个位置是从1开始而非从0开始。
scala& hostPort._1
res0: String = localhost
scala& hostPort._2
res1: Int = 80
元组可以很好地和模式匹配配合使用。
hostPort match {
case (&localhost&, port) =& ...
case (host, port) =& ...
创建一个包含2个值的元组有一个很简单的方式:-&
scala& 1 -& 2
res0: (Int, Int) = (1,2)
参考 《Effective Scala》中关于(拆封一个元组)的观点。
Map里可以存放基本的数据类型。
Map(1 -& 2)
Map(&foo& -& &bar&)
这个看起来是一个特殊的语法,不过回想一下前面我们讨论元组的时候,-&符号是可以用来创建元组的。
Map()可以使用我们在第一节里讲到的可变参数的语法:Map( 1 -& "one", 2 -& "two"),它会被扩展为Map((1,"one"),(2,"two")),其中第一个元素参数是key,第二个元素是value。
Map里也可以包含Map,甚至也可以把函数当作值存在Map里。
Map(1 -& Map(&foo& -& &bar&))
Map(&timesTwo& -& { timesTwo(_) })
Option是一个包含或者不包含某些事物的容器。
Option的基本接口类似于:
trait Option[T] {
def isDefined: Boolean
def get: T
def getOrElse(t: T): T
Option本身是泛型的,它有两个子类:Some[T]和None
我们来看一个Option的示例: Map.get使用Option来作为它的返回类型。Option的作用是告诉你这个方法可能不会返回你请求的值。
scala& val numbers = Map(1 -& &one&, 2 -& &two&)
numbers: scala.collection.immutable.Map[Int,String] = Map((1,one), (2,two))
scala& numbers.get(2)
res0: Option[java.lang.String] = Some(two)
scala& numbers.get(3)
res1: Option[java.lang.String] = None
现在,我们要的数据存在于这个Option里。那么我们该怎么处理它呢?
一个比较直观的方法就是根据isDefined方法的返回结果作出不同的处理。
//如果这个值存在的话,那么我们把它乘以2,否则返回0。
val result = if (res1.isDefined) {
res1.get * 2
不过,我们更加建议你使用getOrElse或者模式匹配来处理这个结构。
getOrElse让你可以很方便地定义一个默认值。
val result = res1.getOrElse(0) * 2
模式匹配可以很好地和Option进行配合使用。
val result = res1 match { case Some(n) =& n * 2 case None =& 0 }
参考 《Effective Scala》中关于 的内容。
函数组合器
List(1,2,3) map squared会在列表的每个元素上分别应用squared函数,并且返回一个新的列表,可能是List(1,4,9)。我们把类似于map这样的操作称为组合器。(如果你需要一个更好的定义,你或许会喜欢Stackoverflow上的。
在列表中的每个元素上计算一个函数,并且返回一个包含相同数目元素的列表。
scala& numbers.map((i: Int) =& i * 2)
res0: List[Int] = List(2, 4, 6, 8)
或者传入一个部分计算的函数
scala& def timesTwo(i: Int): Int = i * 2
timesTwo: (i: Int)Int
scala& numbers.map(timesTwo _)
res0: List[Int] = List(2, 4, 6, 8)
foreach和map相似,只不过它没有返回值,foreach只要是为了对参数进行作用。
scala& numbers.foreach((i: Int) =& i * 2)
没有返回值。
你可以尝试把返回值放在一个变量里,不过它的类型应该是Unit(或者是void)
scala& val doubled = numbers.foreach((i: Int) =& i * 2)
doubled: Unit = ()
移除任何使得传入的函数返回false的元素。返回Boolean类型的函数一般都称为断言函数。
scala& numbers.filter((i: Int) =& i % 2 == 0)
res0: List[Int] = List(2, 4)
scala& def isEven(i: Int): Boolean = i % 2 == 0
isEven: (i: Int)Boolean
scala& numbers.filter(isEven _)
res2: List[Int] = List(2, 4)
zip把两个列表的元素合成一个由元素对组成的列表里。
scala& List(1, 2, 3).zip(List(&a&, &b&, &c&))
res0: List[(Int, String)] = List((1,a), (2,b), (3,c))
partition根据断言函数的返回值对列表进行拆分。
scala& val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala& numbers.partition(_ %2 == 0)
res0: (List[Int], List[Int]) = (List(2, 4, 6, 8, 10),List(1, 3, 5, 7, 9))
find返回集合里第一个匹配断言函数的元素
scala& numbers.find((i: Int) =& i & 5)
res0: Option[Int] = Some(6)
drop & dropWhile
drop丢弃前i个元素
scala& numbers.drop(5)
res0: List[Int] = List(6, 7, 8, 9, 10)
dropWhile移除前几个匹配断言函数的元素。例如,如果我们从numbers列表里dropWhile奇数的话,1会被移除(3则不会,因为它被2所“保护”)。
scala& numbers.dropWhile(_ % 2 != 0)
res0: List[Int] = List(2, 3, 4, 5, 6, 7, 8, 9, 10)
scala& numbers.foldLeft(0)((m: Int, n: Int) =& m + n)
res0: Int = 55
0是起始值(注意numbers是一个List[Int]),m是累加值。
更加直观的来看:
scala& numbers.foldLeft(0) { (m: Int, n: Int) =& println(&m: & + m + & n: & + n); m + n }
m: 10 n: 5
m: 15 n: 6
m: 21 n: 7
m: 28 n: 8
m: 36 n: 9
m: 45 n: 10
res0: Int = 55
这个和foldLeft相似,只不过是方向相反。
scala& numbers.foldRight(0) { (m: Int, n: Int) =& println(&m: & + m + & n: & + n); m + n }
m: 10 n: 0
m: 9 n: 10
m: 8 n: 19
m: 7 n: 27
m: 6 n: 34
m: 5 n: 40
m: 4 n: 45
m: 3 n: 49
m: 2 n: 52
m: 1 n: 54
res0: Int = 55
flatten可以把嵌套的结构展开。
scala& List(List(1, 2), List(3, 4)).flatten
res0: List[Int] = List(1, 2, 3, 4)
flatMap是一个常用的combinator,它结合了map和flatten的功能。flatMap接收一个可以处理嵌套列表的函数,然后把返回结果连接起来。
scala& val nestedNumbers = List(List(1, 2), List(3, 4))
nestedNumbers: List[List[Int]] = List(List(1, 2), List(3, 4))
scala& nestedNumbers.flatMap(x =& x.map(_ * 2))
res0: List[Int] = List(2, 4, 6, 8)
可以把它当作map和flatten两者的缩写:
scala& nestedNumbers.map((x: List[Int]) =& x.map(_ * 2)).flatten
res1: List[Int] = List(2, 4, 6, 8)
这个调用map和flatten的示例是这些函数的类“组合器”特点的展示。
See Also Effective Scala has opinions about .
参考 《Effective Scala》中关于的内容.
广义的函数组合器
现在,我们学习了一大堆处理集合的函数。
不过,我们更加感兴趣的是怎么写我们自己的函数组合器。
有趣的是,上面展示的每个函数组合器都是可以通过fold来实现的。我们来看一些示例。
def ourMap(numbers: List[Int], fn: Int =& Int): List[Int] = {
numbers.foldRight(List[Int]()) { (x: Int, xs: List[Int]) =&
fn(x) :: xs
scala& ourMap(numbers, timesTwo(_))
res0: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
为什么要List[Int]?因为Scala还不能聪明到知道你需要在一个空的Int列表上来进行累加。
如何处理好Map?
我们上面所展示的所有函数组合器都能都Map进行处理。Map可以当作是由键值对组成的列表,这样你写的函数就可以对Map里的key和value进行处理。
scala& val extensions = Map(&steve& -& 100, &bob& -& 101, &joe& -& 201)
extensions: scala.collection.immutable.Map[String,Int] = Map((steve,100), (bob,101), (joe,201))
现在过滤出所有分机号码小于200的元素。
scala& extensions.filter((namePhone: (String, Int)) =& namePhone._2 & 200)
res0: scala.collection.immutable.Map[String,Int] = Map((steve,100), (bob,101))
因为你拿到的是一个元组,所以你不得不通过它们的位置来取得对应的key和value,太恶心了!
幸运的是,我们实际上可以用一个模式匹配来优雅地获取key和value。
scala& extensions.filter({case (name, extension) =& extension & 200})
res0: scala.collection.immutable.Map[String,Int] = Map((steve,100), (bob,101))
为什么这样也可以呢?为什么可以直接传入一个局部的模式匹配呢?
这个内容就留在下周吧!
英文原文: ,翻译:–
本文链接:
【如需转载,请在正文中标注并保留原文链接、译文链接和译者等信息,谢谢合作!】
关于作者:
Java开发工程师,业余翻译
你这明显有问题,你这开辟了5个线程,每个线程都执行50万次操作,就等于=250000...
关于ImportNew
ImportNew 专注于 Java 技术分享。于日 11:11正式上线。是的,这是一个很特别的时刻 :)
ImportNew 由两个 Java 关键字 import 和 new 组成,意指:Java 开发者学习新知识的网站。 import 可认为是学习和吸收, new 则可认为是新知识、新技术圈子和新朋友……
新浪微博:
推荐微信号
反馈建议:@
广告与商务合作QQ:
– 好的话题、有启发的回复、值得信赖的圈子
– 写了文章?看干货?去头条!
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 活跃 & 专业的翻译小组
– 国内外的精选博客文章
– UI,网页,交互和用户体验
– JavaScript, HTML5, CSS
– 专注Android技术分享
– 专注iOS技术分享
– 专注Java技术分享
– 专注Python技术分享
& 2017 ImportNew  Scala 的 if 如同许多其它语言中的一样工作。它测试一个状态并据其是否为真,执行两个分支中的一个:
var filename = "default.txt"
if (!args.isEmpty)
filename = args(0)
  由于 Scala 的 if 是能返回值的表达式,可以改成用 val 的更函数式的风格:
val filename =
if (!args.isEmpty) args(0)
else "default.txt"
  使用 val 而不是 var 的第二点好处是他能更好地支持等效推论:equational reasoning。在表达式没有副作用的前提下,引入的变量等效于计算它的表达式。因此,无论何时都可以用表达式替代变量名:
println(if (!args.isEmpty) args(0) else "default.txt")
while 循环
  Scala 的 while 循环表现的和在其它语言中一样。包括一个状态和循环体,只要状态为真,循环体就一遍遍被执行:
def gcdLoop(x: Long, y: Long): Long = {
while (a != 0) {
val temp = a
  Scala 也有 do-while 循环。除了把状态测试从前面移到后面之外,与 while 循环没有区别。
  While 和 do-while 结构被称为&循环&,不是表达式,因为它们不产生有意义的结果,结果的类型是 Unit 。说明产生的值的类型为 Unit 。被称为 unit value ,写做 () 。 () 的存在是 Scala 的 Unit 不同于 Java 的 void 的地方:
cala& def greet() { println("hi") }
greet: ()Unit
scala& greet() == ()
res0: Boolean = true
  由于方法体之前没有等号, greet 被定义为结果类型为 Unit 的过程。因此, greet 返回 unit 值 () 因此在比较 greet 的结果和 unit 值 () ,的相等性,产生true。
for 表达式
枚举集合类
  用 for 做的最简单的事情就是把一个集合类的所有元素都枚举一遍:
val filesHere = (new java.io.File(".")).listFiles
for (file &- filesHere)
println(file)
  代码先创建指向当前目录 &.& 的文件,调用 listFiles 方法,返回 File 对象数组保存在 filesHere 变量中,通过发生器:generator的语法&file &- filesHere&遍历了 filesHere 的元素,每一次枚举 file 的新 val 就被元素值初始化并被打印出来。
  for 表达式语法对任何种类的集合类都有效而不只是数组,可以使用类似于 &1 to 5& 这样的语法创建一个 Range ,然后用 for 枚举:
scala& for (i &- 1 to 4)
| println("lteration" + i)
lteration1
lteration2
lteration3
lteration4
  有些时候不想枚举一个集合类的全部元素。而是想过滤出一个子集。可以通过把过滤器:filter:一个 if 子句加到 for 的括号里做到:
val filesHere = (new java.io.File(".")).listFiles
for (file &- filesHere if file.getName.endsWith(".scala"))
println(file)
  也可以这么写:
for (file &- filesHere)
if (file.getName.endsWith(".scala"))
println(file)
  如果愿意的话,可以包含更多的过滤器。只要不断加到子句里即可:
file &- filesHere
if file.isF
if file.getName.endsWith(".scala")
)println(file)
  如果在发生器中加入超过一个过滤器, if 子句必须用分号分隔。
  如果加入多个 &- 子句就得到嵌套的&循环&:
def fileLines(file: java.io.File) =
scala.io.Source.fromFile(file).getLines.toList
def grep(pattern: String) =
file &- filesHere
if file.getName.endsWith(".scala")
line &- fileLines(file)
if line.trim.matches(pattern)
} println(file + ": " + line.trim)
grep(".*gcd.*")
  代码展示的 for 表达式有两个嵌套循环,外层循环枚举 filesHere ,内层的枚举所有以 .scala 结尾的文件的 fileLines(file) 。可以使用大括号代替小括号环绕发生器和过滤器,这样的好处是可以省略一些使用小括号必须加的分号。
mid-stream (流间) 变量绑定
  注意到前段代码中重复出现的表达式 line.trim ,这不是个可忽略的计算,如果想每次只算一遍,可以用等号 (=) 把结果绑定到新变量做到这点,绑定的变量被当做用 val 引入和使用,不过不用带关键字 val :
def grep(pattern: String) =
file &- filesHere
if file.getName.endsWith(".scala")
line &- fileLines(file)
trimmed = line.trim
if trimmed.matches(pattern)
} println(file + ": " + trimmed)
grep(".*gcd.*")
  名为 trimmed 的变量被引入 for 表达式,并被初始化为 line.trim 的结果值。之后的 for 表达式就可以在两个地方使用这个新变量,一次在 if 中,一次在 println 中。
制造新集合
  可以创建一个值去记住每一次的迭代,只要在 for 表达式之前加上关键字 yield :
def scalaFiles =
file &- filesHere
if file.getName.endsWith(".scala")
} yield file
  for 表达式在每次执行的时候会制造一个值,当 for 表达式完成的时候,结果将是一个包含了所有产生的值的集合,结果集合的类型基于枚举子句处理的集合类型。 for-yield 表达式的语法:
for {子句} yield {循环体}
  yield 在整个循环体之前,即使循环体是一个被大括号包围的代码块,也一定把 yield 放在左括号之前而不是代码的最后一个表达式之前:
for (file &-filesHere if file.getName.endsWith(".scala")) {
yield file // 语法错误!
使用 try 表达式处理异常
  异常的抛出看上去与 Java 的一模一样。首先创建一个异常对象然后用 throw 关键字抛出:
throw new IllegalArgumentException
  Scala 里, throw 也是有结果类型的表达式,抛出异常的类型是 Nothing ,尽管 throw 不实际得出任何值,但还是可以把它当做表达式。
  用来捕获异常的语法如下:
import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException
val f = new FileReader("input.txt")
// Use and close file
case ex: FileNotFoundException =& // Handle missing file
case ex: IOException =& // Handle other I/O error
  这个 try-catch 表达式的行为与其它语言中的异常处理一致。程序体被执行,如果抛出异常,每个 catch 子句依次被尝试。本例中,如果异常是 FileNotFoundException ,那么第一个子句将被执行。如果是 IOException 类型,第二个子句将被执行。如果都不是,那么try-catch将终结并把异常上升出去。
finally 子句
  和其它大多数 Scala 控制结构一样, try-catch-finally 也产生值。 Scala 的行为与 Java 的差别仅源于 Java 的 try-finally 不产生值。 Java 里如果 finally 子句包含一个显式返回语句,或抛出一个异常,这个返回值或异常将&凌驾&于任何之前源于 try 代码块或某个它的 catch 子句产生的值或异常之上:
def f(): Int = try { return 1 } finally { return 2 }
  调用 f() 产生结果值 2 ,相反:
def g(): Int = try { 1 } finally { 2 }
  调用 g() 产生 1 。
match 表达式
  Scala 的匹配表达式允许在许多可选项:alternative中做选择,就好象其它语言中的 switch 语句。 Match 表达式可以你使用任意的模式:pattern做选择:
val firstArg = if (args.length & 0) args(0) else ""
firstArg match {
case "salt" =& println("pepper")
case "chips" =& println("salsa")
case "eggs" =& println("bacon")
case _ =& println("huh?")
  match 缺省情况用下划线 (_) 说明,这是常用在 Scala 里作为占位符表示完全不清楚的值的通配符。
  Scala 里的 case 匹配表达式可以使任何种类的常量,每个可选项最后没有 break ,但是 break 是隐含的。 match 表达式也能产生值:
val firstArg = if (!args.isEmpty) args(0) else ""
val friend =
firstArg match {
case "salt" =& "pepper"
case "chips" =& "salsa"
case "eggs" =& "bacon"
case _ =& "huh?"
println(friend)
  Scala 程序里的变量定义有一个能够使用的范围:scope。大括号通常引入了一个新的范围,任何定义在大括号里的东西在括号之后就脱离了范围。
  一旦变量被定义了就不能在同一范围内定义同样的名字,但是可以在内部范围内定义与外部范围内名称相同的变量,用大括号括起来即为内部范围。内部变量会遮蔽同名的外部变量。
阅读(...) 评论()scala怎么定义无参构造函数? - 知乎6被浏览1536分享邀请回答class MyClass() {
object MyClass {
def apply(): MyClass = {
然后, 你就可以这样构造类了 (还不用写 new 关键字):val my = MyClass()
当然, 一般我要把 MyClass 写成这样:class MyClass private() {
这里的 private 的作用是把默认构造函数藏起来, 不允许用户这么写:val my = new MyClass()
51 条评论分享收藏感谢收起scala& class A {
//do anything you want
println("Hi, the construtor invoked here..")
defined class A
scala& val a = new A
Hi, the construtor invoked here..
a: A = A@1339a0dc
上面的Scala代码基本等价于下面的Java代码:public class A {
public A() {
//do anything you want
println("Hi, the construtor invoked here..");
58 条评论分享收藏感谢收起与世界分享知识、经验和见解

我要回帖

更多关于 scala 辅助构造器 的文章

 

随机推荐