apply方法
当一个类或者对象有一个主要的用途的时候,apply方法可以提供一种很好的语法糖(syntactic sugar)。
1
2
3
4
5
6
7
8
9
10
|
scala>
class
Foo {}
defined
class
Foo
scala> object FooMaker {
| def apply() =
new
Foo
| }
defined module FooMaker
scala> val newFoo = FooMaker()
newFoo: Foo = Foo
@5b83f762
|
或者
1
2
3
4
5
6
7
8
9
10
|
scala>
class
Bar {
| def apply() =
0
| }
defined
class
Bar
scala> val bar =
new
Bar
bar: Bar = Bar
@47711479
scala> bar()
res8: Int =
0
|
这样来看实例对象,好像我们是在调用一个方法。后面会详细介绍这个!
对象
对象都是用来保持一个类的单个实例。经常在工厂里用到。
1
2
3
4
5
6
7
8
|
object Timer {
var count =
0
def currentCount(): Long = {
count +=
1
count
}
}
|
怎么去使用
1
2
|
scala> Timer.currentCount()
res0: Long =
1
|
类和对象可以重名。这样的对象被称为“伴随对象(Companion Object)”。我们一般在工厂里使用伴随对象。
这里有个简单的示例,它的作用是使得创建对象实例的时候不需要用‘new’。
1
2
3
4
5
|
class
Bar(foo: String)
object Bar {
def apply(foo: String) =
new
Bar(foo)
}
|
函数即对象
在Scala里,我们经常讨论对象-函数编程。它表示什么呢?函数究竟是什么?
函数是一系列的trait。确切地说,有一个参数的函数是Function1 trait的一个实例。这个trait定义了我们之前学到的apply()
的语法糖,它允许你像调用函数一样调用对象。
1
2
3
4
5
6
7
|
scala> object addOne
extends
Function1[Int, Int] {
| def apply(m: Int): Int = m +
1
| }
defined module addOne
scala> addOne(
1
)
res2: Int =
2
|
在Scala里有Function1到22。为什么是22?这是一个任意的魔数。我从来没有遇到需要22个参数的函数,所以这个数字还是很有效的。
apply的语法糖使得对象和函数的编程能够组合在一起。你可以把对象作为参数进行传递,同时也可以把它们当作函数使用,而实际上函数也只不过是类的实例。
那这样是不是意味着每次你在类里定义一个方法,那么你就会得到Function的一个实例呢?不,类里的方法仅仅是普通的方法。在repl里单独定义的方法才是Function的实例。
类也可以继承函数,然后这些类的实例就可以通过()来调用。
1
2
3
4
5
6
7
8
9
10
|
scala>
class
AddOne
extends
Function1[Int, Int] {
| def apply(m: Int): Int = m +
1
| }
defined
class
AddOne
scala> val plusOne =
new
AddOne()
plusOne: AddOne =
scala> plusOne(
1
)
res0: Int =
2
|
extends Function1[Int,Int]
的一种比较好的简写是extends (Int => Int)
1
2
3
|
class
AddOne
extends
(Int => Int) {
def apply(m: Int): Int = m +
1
}
|
1
|
|
包
你可以通过包来组织你的代码。
1
|
package
com.twitter.example
|
在一个文件的顶部声明包,那么这个文件里的所有的东西都是在这个包里。
值和函数不能在类和对象外面。对象对于组织静态函数是很有用的。
1
2
3
4
5
6
|
package
com.twitter.example
object colorHolder {
val BLUE =
"Blue"
val RED =
"Red"
}
|
现在你可以直接访问里面的成员
1
|
println(
"the color is: "
+ com.twitter.example.colorHolder.BLUE)
|
当你在scala repl里定义这个对象时,它会提示什么:
1
2
3
4
5
|
scala> object colorHolder {
| val Blue =
"Blue"
| val Red =
"Red"
| }
defined module colorHolder
|
上面的信息暗示你scala的设计者把对象设计成为Scala的模块系统的一部分。
模式匹配
Scala中最有用的一个功能。
对值进行匹配
1
2
3
4
5
6
7
|
val times =
1
times match {
case
1
=>
"one"
case
2
=>
"two"
case
_ =>
"some other number"
}
|
受保护的匹配
1
2
3
4
5
|
times match {
case
i
if
i ==
1
=>
"one"
case
i
if
i ==
2
=>
"two"
case
_ =>
"some other number"
}
|
注意我们如何捕获变量’i'里的值。
最后的一条语句中的_
是一个通配符;它保证我们能够处理任何输入。否则的话,如果我们传入一个不匹配的值,将会出现runtime error。我们后面会继续讨论这个。
参考 《Effective Scala》中有关于什么时候使用模式匹配</>和模式匹配格式的讨论。《A Tour of Scala》中讲解了模式匹配。
针对类型进行匹配
你可以使用match
来对不同的类型的值进行不同的处理。
1
2
3
4
5
6
7
8
9
|
def bigger(o: Any): Any = {
o match {
case
i: Int
if
i <
0
=> i -
1
case
i: Int => i +
1
case
d: Double
if
d <
0.0
=> d -
0.1
case
d: Double => d +
0.1
case
text: String => text +
"s"
}
}
|
对类的成员进行匹配
回想一下我们之前的caculator的示例。
我们通过它们的类型来进行归类。
1
2
3
4
5
6
|
def calcType(calc: Calculator) = calc match {
case
calc.brand ==
"hp"
&& calc.model ==
"20B"
=>
"financial"
case
calc.brand ==
"hp"
&& calc.model ==
"48G"
=>
"scientific"
case
calc.brand ==
"hp"
&& calc.model ==
"30B"
=>
"business"
case
_ =>
"unknown"
}
|
噢,这样写太麻烦了。幸运的是Scala提供了一些有用的工具来处理这种场景。
Case Classes
case class可以用来方便地存储和匹配类的内容。你不需要用new
来构造它们。
1
2
3
4
5
|
scala>
case
class
Calculator(brand: String, model: String)
defined
class
Calculator
scala> val hp20b = Calculator(
"hp"
,
"20b"
)
hp20b: Calculator = Calculator(hp,20b)
|
case class会自动根据传入的参数生成equlity和toString方法。
1
2
3
4
5
6
7
8
|
scala> val hp20b = Calculator(
"hp"
,
"20b"
)
hp20b: Calculator = Calculator(hp,20b)
scala> val hp20B = Calculator(
"hp"
,
"20b"
)
hp20B: Calculator = Calculator(hp,20b)
scala> hp20b == hp20B
res6: Boolean =
true
|
case class可以像正常类一样拥有方法。
通过Case Class来进行模式匹配
case class的设计就是为了进行模式匹配。我们来通过它简化之前的calculator 归类程序。
1
2
3
4
5
6
7
8
9
|
val hp20b = Calculator(
"hp"
,
"20B"
)
val hp30b = Calculator(
"hp"
,
"30B"
)
def calcType(calc: Calculator) = calc match {
case
Calculator(
"hp"
,
"20B"
) =>
"financial"
case
Calculator(
"hp"
,
"48G"
) =>
"scientific"
case
Calculator(
"hp"
,
"30B"
) =>
"business"
case
Calculator(ourBrand, ourModel) =>
"Calculator: %s %s is of unknown type"
.format(ourBrand, ourModel)
}
|
最后一行的另外一种写法
1
|
case
Calculator(_, _) =>
"Calculator of unknown type"
|
或者我们不用把它当作Calculator来处理。
1
|
case
_ =>
"Calculator of unknown type"
|
也或者,我们可以用另外的名字来绑定这个匹配。
1
|
case
c
@Calculator
(_, _) =>
"Calculator: %s of unknown type"
.format(c)
|
异常
在Scala里,异常的处理是通过一个使用模式匹配的try-catch-finally语法进行处理的。
1
2
3
4
5
6
7
|
try
{
remoteCalculatorService.add(
1
,
2
)
}
catch
{
case
e: ServerIsDownException => log.error(e,
"the remote calculator service is unavailble. should have kept your trustry HP."
)
}
finally
{
remoteCalculatorService.close()
}
|
try
也是面向表达式的
1
2
3
4
5
6
7
8
9
10
|
val result: Int =
try
{
remoteCalculatorService.add(
1
,
2
)
}
catch
{
case
e: ServerIsDownException => {
log.error(e,
"the remote calculator service is unavailble. should have kept your trustry HP."
)
0
}
}
finally
{
remoteCalculatorService.close()
}
|
这个并不是一种很好的编码方式,而只是try-catch-finally返回表达式的一个示例,正如Scala里其他的一样。
Finally里的语句会在异常处理完之后执行,并且它不是表达式的一部分。
http://www.importnew.com/3578.html