一、Scala的层级

1.1类层级

  • Scala中,Any是所其他类的超类,在底端定义了一些有趣的类NULL和Nothing,是所有其他类的子类。

  • 根类Any有两个子类:AnyVal和AnyRef。其中AnyVal是Scala里每个内建值类的父类
scala> new Int
<console>:12: error: class Int is abstract; cannot be instantiated
new Int

  

1.2底层类型

在Scala类层级中,可看到scala.Null和scala.Nothing。它们是用统一的方式处理Scala面对对象类型的某些“边界情况”的特殊类型。

  • Null类是null引用对象的类型,它是每个引用类的子类,Null不兼容值类型,例如,不能把null值赋给整数变量:
scala> val i: Int = null
<console>:11: error: an expression of type Null is ineligible for implicit conversion
val i: Int = null
^

  Nothing类型在Scala的类层级的最底层,它是任何其他类型的的子类型。Nothing的一个用处是它标明了不正常的终止。例如Scala的标准库中的Predef对象有一个error方法,如下定义:

def error(message:Sring):Nothing=
throw new RuntimeException(message)

error 的返回类型是Nothing,告诉用户方法不是正常返回(是抛出异常)。因为Nothing是任何类的子类,所有可以灵活使用向error这样的方法,例如:

scala> def error(message:String):Nothing =
| throw new RuntimeException(message)
error: (message: String)Nothing scala> def divide(x:Int,y:Int):Int=
| if(y!=0) x/y else error("can't divide by zero")
divide: (x: Int, y: Int)Int scala> divide(7,2)
res5: Int = 3 scala> divide(7,0)
java.lang.RuntimeException: can't divide by zero
at .error(<console>:12)
at .divide(<console>:13)
... 28 elided scala>

  

二、函数和闭包

2.1方法

  • 定义函数最通用是方法是作为某个对象的成员。这种函数被称为方法,作为例子:
 import scala.io.Source
object LongLines{
def processFile(filename:String,width:Int){
val source = Source.fromFile(filename)
for(line<-source.getLines)
processFile(filename,width,line)
}
private def processFile(filename:String,width:Int,line:String){
if(line.length>width)
println(filename+":"+line.trim)
} } object FileLongLines{
def main(args:Array[String]){
val width=args(0).toInt
for(arg<-args.drop(1))
LongLines.processFile(arg,width)
}
}

2.2本地函数

上节processFile方法的建立演示了函数式编程的设计原则,问题是这些帮助函数的名称可能污染程序的命名空间。

Scala中的解决方法:一种是私有方法。

  • 另一种是把函数定义在别的函数内。就好像本地变量那样,这种本地函数仅在包含它的代码块中可见。举例:
 def processFile(filename:String,width:Int){

        def processLine(filename:String,width:Int,line:String){
if(line.length>width)
println(filename+":"+line.trim)
}
val source = Source.fromFile(filename)
for(line<-source.getLines)
processFile(filename,width,line)
}

  

例子中通过私有方法转化为局部方法,processLine的定义放在processFile定义里,作为本地函数,processLine的范围局限在processFile之内,外部无法访问。

  • 带局部processLine方法的LongLines
 def processFile(filename:String,width:Int){

        def processLine(line:String){
if(line.length>width)
println(filename+":"+line.trim)
}
val source = Source.fromFile(filename)
for(line<-source.getLines)
processFile(line)
}

这种对外层函数入参的直接使用是Scala里通用的嵌套思想的平常但也很有用

2.3头等函数

Scala的函数是头等函数,不仅可以定义和调用函数,还可以把它们写成匿名的字面量,并把他们作为值传递,

函数字面量被编译进类,并在运行期间实例化为函数值。因此函数字面量和值的区别在于函数字面量存在于原代码,而函数值作为对象存在于运行期。这个区别很像类(源代码)和对象(运行期)之间的关系。

=>指明这个函数把左边的东西(任何整数x)转化为右边的东西。所有,这个函数可以把任何整数x映射为x+1。

函数值是对象,所有如果你愿意,可以将其存入变量。它们也是函数,所有你可以使用通常的括号函数调用它们。

scala> var increase=(x:Int)=>x+1
increase: Int => Int = $$Lambda$1149/268616862@62eb918 scala> increase(4)
res7: Int = 5

  

2.4部分应用函数

scala> val someNumbers=List(-11,-10,-5,0,5,10)
someNumbers: List[Int] = List(-11, -10, -5, 0, 5, 10) scala> someNumbers.foreach(x:Int)
<console>:13: error: not found: value x
someNumbers.foreach(x:Int)
^
<console>:13: error: type mismatch;
found : Int
required: Int => ?
someNumbers.foreach(x:Int)
^ scala> someNumbers.foreach(x:Int)=>println(x)
<console>:1: error: ';' expected but '=>' found.
someNumbers.foreach(x:Int)=>println(x)
^ scala> someNumbers.foreach((x:Int)=>println(x))
-11
-10
-5
0
5
10 scala> someNumbers.filter((x:Int)=>x>0)
res10: List[Int] = List(5, 10) scala> someNumbers.filter((x)=>x>0)
res11: List[Int] = List(5, 10) scala> someNumbers.filter(x=>x>0)
res12: List[Int] = List(5, 10) scala> someNumbers.filter(_>0)
res13: List[Int] = List(5, 10) scala> val f=_+_
<console>:11: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2))
val f=_+_
^
<console>:11: error: missing parameter type for expanded function ((x$1: <error>, x$2: <error>) => x$1.$plus(x$2))
val f=_+_
^ scala> val f=(_:Int)+(_:Int)
f: (Int, Int) => Int = $$Lambda$1180/712034517@6d0ef6dc scala> f(2,6)
res14: Int = 8

部分应用函数是一种表达式,不需要提供需要的所有参数。代之以提供部分,或者不提供所需参数。

闭包

scala> (x:Int)=>x+more
<console>:12: error: not found: value more
(x:Int)=>x+more
^
//声明more
scala> val more=1
more: Int = 1
scala> val addMore=(x:Int)=>x+more
addMore: Int => Int = $$Lambda$1206/2005145495@773eb14c
scala> addMore(5)
res21: Int = 6

  

依照这个函数字面量在运行时创建的函数值(对象)被称为闭包

重复函数

Scala中,可以指明函数的最后一个参数是重复的,从而允许客户向函数传入可变长度参数列表。想要标注一个重复参数,可在参数类型之后放一个星号。如:

scala> def echo(args:String*)=
| for (arg<-args) println(arg)
echo: (args: String*)Unit scala> echo() scala> echo("one")
one scala> echo("one","hello!")
one
hello!
函数内部,重复函数的类型是声明参数类型的数组。因此,echo函数被声明为类型“String*”的args的类型实际上是Array[String]。然而,如果你有一个合适的数组,并尝试把它当作重复参数传入,将得到编译器错误:
scala> val arr=Array("What's","up","doc?")
arr: Array[String] = Array(What's, up, doc?) scala> echo(arr)
<console>:14: error: type mismatch;
found : Array[String]
required: String
echo(arr)
^

  

要实现这个做法,需要在数组参数后添加一个冒号和一个_*,如下:

scala> echo(arr:_*)
What's
up
doc?

  

Scala实践5的更多相关文章

  1. Scala实践14

    1.Scala的future 创建future import scala.concurrent._ import ExecutionContext.Implicits.global object Fu ...

  2. Scala实践13

    1.隐式参数 方法可以具有隐式参数列表,由参数列表开头的implicit关键字标记.如果该参数列表中的参数没有像往常一样传递,Scala将查看它是否可以获得正确类型的隐式值,如果可以,则自动传递. S ...

  3. Scala实践12

    1.内部类和抽象类型成员作为对象成员 内部类 在Scala中,可以让类将其他类作为成员.这些内部类是封闭类的成员.在Scala中,这样的内部类绑定到外部对象.假设希望编译器在编译时阻止我们混合哪些节点 ...

  4. Scala实践11

    1.1泛型类 泛型类是将类型作为参数的类.它们对集合类特别有用. 定义泛类型:泛型类将类型作为方括号内的参数[].一种惯例是使用字母A作为类型参数标识符,但是可以使用任何参数名称. class Sta ...

  5. Scala实践10

    1.模式匹配 模式匹配是一种根据模式检查值的机制.它是switch(Java中语句)的更强大版本,它同样可以用来代替一系列if / else语句. 句法 匹配表达式具有值,match关键字和至少一个c ...

  6. Scala实践9

    1.特征 Traits用于在类之间共享接口和字段.它们类似于Java 8的接口.类和对象可以扩展特征,但是特征不能被实例化,因此没有参数. 定义一个特征 最小特征只是关键字trait和标识符: tra ...

  7. Scala实践6

    1  if表达式 Scala中if...else..表达式是有返回值的,如果if和else返回值类型不一样,则返回Any类型. scala> val a3=10 a3: Int = 10 sca ...

  8. Scala实践8

    1.1继承类 使用extends关键字,在定义中给出子类需要而超类没有的字段和方法,或者重写超类的方法. class Person { var name = "zhangsan" ...

  9. Scala实践7

    一.类 1.1简单类和无参方法 类的定义通过class关键字实现 scala> class Dog { | private var leg = 4 | def shout(content: St ...

随机推荐

  1. dotnet 设计规范 · 数组定义

    本文告诉大家数组定义需要知道的规范,本文翻译 docs dotnet ✓ 建议在公开的 API 使用集合而不是数组.集合可以提供更多的信息. X 不建议设置数组类型的字段为只读.虽然用户不能修改字段, ...

  2. UVA 11400"Lighting System Design"

    传送门 错误思路 正解 AC代码 参考资料: [1]:https://www.cnblogs.com/Kiraa/p/5510757.html 题意: 现给你一套照明系统,这套照明系统共包含 n 种类 ...

  3. H3C DHCP中继显示及维护

  4. 2018-2-13-win10-uwp-图标制作器

    title author date CreateTime categories win10 uwp 图标制作器 lindexi 2018-2-13 17:23:3 +0800 2018-2-13 17 ...

  5. CodeForces Goodbye 2017

    传送门 A - New Year and Counting Cards •题意 有n张牌,正面有字母,反面有数字 其中元音字母$a,e,o,i,u$的另一面必须对应$0,2,4,6,8$的偶数 其他字 ...

  6. PowerShell 通过 WMI 获取系统安装软件

    本文告诉大家如何通过 WMI 获取系统安装的软件 通过 Win32_Product 可以获取系统安装的软件 Get-WmiObject Win32_Product | Format-List Capt ...

  7. Simple Robot Gym - 101102I (思维)

    SaMer is building a simple robot that can move in the four directions: up (^), down (v), left (<) ...

  8. PDF.JS 读取文件流前端展示 C#

    最近再搞PDF得展示问题,因为aspose.pdf成本太高,只能使用pdf.js这个开源强大的前端东东了. 在百度了很久后 网上大都是node,java,php的事例,有位大哥的是C#的后台代码按他写 ...

  9. linux查看文件内容跳到文件底部和回到文件顶部的快捷键

    有时候需要查看一些日志文件,然后要从底部开始查看的话 可以按 shift+g  即可跳到文件底部 要返回文件顶部的时候 按 gg即可

  10. JMeter JMS测试计划

    在本节中,我们将学习如何编写一个简单的测试计划来测试Java Messaging Service(JMS). 出于测试目的,我们使用Apache ActiveMQ.有各种JMS服务器,如:glassf ...