SCALA 高中信息技术好学吗?

Scala学习笔记 - fuliang - ITeye技术网站
博客分类:
一、变量:
val v1 = 2;//变量,不能重新赋值,函数式语言大量提倡使用val变量,Erlang所有的变量都是val的
var v2 = 3;//变量,和Java的变量一致
def v3 = v1 * v2;//只是定义v1*v2表达式的名字,并不求值,在使用的求值
lazy val lazyVal = { println("I'm too lazy"); 1 }
println("after lazyVal")
val x = lazyVal
打印出:
after lazyVal
I'm too lazy
二、表达式:
For comprehensioon
val dogBreeds = List("Doberman", "Yorkshire Terrier", "Dachshund",
"Scottish Terrier", "Great Dane", "Portuguese Water Dog")
for (breed &- dogBreeds)
println(breed)
for(bread &- dogBreads
if bread.contains("Terrier");
if !bread.contains("Yorkshire");
)println(bread)
val filteredBreeds = for {
breed &- dogBreeds
if breed.contains("Terrier")
if !breed.startsWith("Yorkshire")
} yield breed
避免使用显式返回
三、条件控制:
while,do...while没有什么特别
if...else
for 表达式:
val filesHere = (new java.io.File(".")).listFiles
for (file &- filesHere)
println(file)
for(i &- 1 to 4){//和Ruby中的1..4一样
println(i)
for(i &-1 util 4){//和Ruby中的1...4一样
println(i)
一切表达式都有返回值,条件控制语句也不例外
val v1 = if(true) 1 else 0
四、函数式编程:
1、一切操作都是函数调用:
1 + 1 等价于 1.+(1)
for (i &- List(1, 2)) {
println(i)
}
//for是函数调用
2、一切函数都可以作为操作符使用:
1 max 2
3、函数嵌套:
def sqrt(x: Double) = {
def sqrtIter(guess: Double, x: Double): Double =
if (isGoodEnough(guess, x)) guess
else sqrtIter(improve(guess, x), x)
def improve(guess: Double, x: Double) =
(guess + x / guess) / 2
def isGoodEnough(guess: Double, x: Double) =
abs(square(guess) x) & 0.001
sqrtIter(1.0, x)
4、函数是一等公民:
(x: Int) =& x + 1//匿名函数
var inc = (x: Int) =& x + 1//赋值给一个变量
val someNumbers = List(-11,-10,-5,0, 5, 10)
someNumbers.foreach((x: Int) =& println(x))
someNumbers.filter((x: Int) =& x & 0)
利用类型推到简化:
someNumbers.foreach(x =& println(x))
使用占位符语法(Placeholder syntax)
someNumbers.filter(_ & 0)
使用Partially applied functions
someNumbers.foreach( println _ )
由于foreach期望一个函数作为参数,所以可以简化为
someNumbers.foreach(println)
var more = 1
var addMore = (x: Int) =& x + more
addMore(10)
结果是11
闭包绑定的是定义时的变量,而不是值
var more = 2
addMore(10)
结果是12
6、尾递归:
递归函数在最后一个操作调用自身
def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
7、偏函数(Partial Function)
def concatUpper(s1: String, s2: String): String = (s1 + " " + s2).toUpperCase
val c = concatUpper("hello,",_:String)
c("world")
偏函数的类型是PartialFunction,他是一个trait,定义了一个函数orElse
val truthier: PartialFunction[Boolean, String] = { case true =& "truthful" }
val fallback: PartialFunction[Boolean, String] = { case x =& "sketchy" }
val tester = truthier orElse fallback
println(tester(1 == 1))
println(tester(2 + 2 == 5))
8、curry化:
def cat(s1: String)(s2: String) = s1 + s2
val c1 = cat("hello,")
c1("world)
普通函数可以转化成curry化的:
def cat(s1: String)(s2: String) = s1 + s2
var carryCat = Function.curried(cat _)
cat("hello,")("world")
9、隐式转换:
Scala有一些常用的类型都有一个RichXxx类型:
4 max 3 就是自动转化成为 RichInt类型
val name: String = "scala"
println(name.capitalize.reverse)
java.lang.String中没有capitalize和reverse,通过
隐式转换成RichString来实现的,Predef里面定义了
implicit def stringWrapper(x: String) = new runtime.RichString(x)
隐式转换函数都用implicit修饰。
10、隐式函数参数(Implicit Function Parameters):
隐式参参数可以在上下文中找到并绑定到同名的变量:
def multiplier(i: Int)(implicit factor: Int) {
println(i * factor)
implicit val factor = 2
multiplier(2)
multiplier(2)(3)
11、call-by-value or call-by-name
def f(x: Int) = x//call-by-value
def f(x: =& Int) = x//call-by-name(参数类型前面带有=&)
//使用call-by-name构建自己的流程控制语句
def myWhile(conditional: =& boolean)(f: =& Unit){
if(conditional)
myWhile(conditional)(f)
var count = 0
myWhile( count & 5){
println("still loop while");
count += 1
12、模式匹配:
函数式语言最重要的概念模式匹配:
匹配常量:
def fib(in: Int): Int = in match{
case n if n &= 0 =& 0
case 1 =& 1
case n =& fib2(n-1) + fib2(n-2)
可以匹配任何类型:
def activity(day: String){
day match{
case "Sunday" =& print("Eat, sleep,repeat...")
case "Saturday" =& print("Hangout with friends...")
case "Monday" =& println("...code for fun...")
常量匹配和Java的switch...case类似,变量匹配使得变量得副作用而得到匹配的值。
元组匹配:
def coordinates(intput: Any){
input match{
case (x,y) =& printf("x=%d,y=%d",x,y);
case _ =& Nothing
List匹配:
def sumOdd(in: List[Int]): Int in match{
case Nil =& 0
case x::rest if x % 2 == 1 =& x + sumOdd(rest)
case _::rest =& sumOdd(rest)
类型匹配:
def typeMatch(in: Any) = in match{
case s: String =& "String, length " + s.length
case i: Int if i & 0 =& "Natural Int"
case i: Int =& "Another Int"
case a: AnyRef =& a.getClass.getName
case _ =& "null"
类似于java的instanceof
case class:
case class Person(name: String,age:Int)
val p = Person("Smith" 20)
equals,hashcode,accessor all ok
case class匹配:
case class Apple()
case class Orange()
case class Book()
def accept(thing: Any){
thing match{
case Apple() =& println("Apple")
case Orangle() =& println("Orange")
case Book() =& println("Book")
case _ =& println("Not accepted")
Sealed class:
匹配的case class是无法穷举的,Sealed class只能在和他相同的文件中定义子类,所以只需要关注
当前文件的case class匹配的列举,并且如果列举不全则编译时有Warning。
sealed abstract class Expr
case class Var(name: String) extends Expr
case class Number(num: Double) extends Expr
case class UnOp(operator: String, arg: Expr) extends Expr
def describe(e: Expr): String = e match{
case Number(x) =& "a number"
case Var(_) =& "a variable"
编译的时候会有Waring:
warning: match is not exhaustive!
missing combination&&&&&&&&&& UnOp
missing combination&&&&&&&&& BinOp
正则表达式作为Extractor
def process(input: String){
val MatchStock = """^(.+):(\d*\.\d+)""".r
input match{
case MatchStock("GooG", price) =& println("Price Of GooG is " + price)
case MatchStock("IBM",price) =& println("Price of IBM is " + price)
case _ =& println("No data for access")
prcoess("GooG:310.84")
13、Stream:
五、面向对象:
1、一切皆是对象
//值也是对象
123.toByte
true.toString
val compare = (x: Int, y: Int) = x & y//函数也是值
2、单例对象:
object Singleton{
val v = 1;
main函数都是写在伴生对象中的
3、没有静态成员:
以为他们的实例也必须是对象的实例
object Dog {
val whatever = "dog" // static field in Java
4、主构造函数:
class Rational(n: Int,d: Int){//主构造函数
def this(n: Int) = this(n,1)////Auxiliary constructors
5、访问子:
没有声明为private的字段自动生成getter,setter方法:
class Time {
var hour = 12
var minute = 0
class Time {
private[this] var h = 12
private[this] var m = 0
def hour: Int = h
def hour_=(x: Int) { h = x }
def minute = m
def minute_=(x: Int) { m = x }
6、覆写override:
覆写关键词是必须的(抽象的是可选的),而不像java的@override是可选的:
class Rational(n: Int, d: Int) extends AnyRef {
//...other code
override def toString = "" + numer + "/" + denom
不光可以覆写函数,还可以覆写字段
class AbstractParent {
def name = "parent";
class ConcreteChild extends AbstractParent {
override val name = "Child"
6、伴生对象:
和类名一样的单例对象成为伴生对象。
在伴生对象中的类和Java的静态成员类似。
7、抽象类型:
类、方法、字段和类型都可以为抽象的。
abstract class AbstractParent {//抽象类
def name: String//抽象字段
class ConcreteChild extends AbstractParent {
val name = "Child"//覆写集成的字段,由于父类是抽象的,所以可以省略override字段
println(new ConcreteChild().name)
8、方法和字段不可以重名:
方法和字段被设置为统一命名空间。无参方法可以省略括号。
7、操作符重载
scala允许操作符作为函数名,使用重载和定义普通的函数类似。
def +()
重载+隐式转换经常一起使用
比c++简单:c++使用operator()+ 和使用operator()进行重载和类型隐式转换,并且
区分为成员还是友元重载。
待补充....
六、类型体系:
待补充...
七、DSL
待补充...
八、Actor
浏览: 1213020 次
来自: 北京
不懂呀。。
按照上面的执行,文件确实是更新了,但是还是找不到kernel, ...
楼主spring 什么版本,我的3.1 ,xml中配置 &lt ...
这样是可以。。不过异常在前端要转义下。不然用户看异常信息有什么 ...十二步学会Scala -1 - alanwu - ITeye技术网站
博客分类:
关于Scala的意义,优劣就先不说了,上Step by Step把人引进来再说,大家一步步进门后再做语言比较也不迟。
参考《First Steps to Scala
/scalazine/articles/steps.html
我先大致根据这篇文章写一些自己的理解,让想学Scala的同学有个感性认识。
读者对象:有Java经验的工程师
第一步:下载和安装Scala
在官网下载
并接压缩,像安装ANT或MAVEN之类的那样,把解压后的bin路径加到path里面去就可以了。
在命令行模式下输入Scala
C:\Documents and Settings\&scala
to Scala version 2.7.5.final (Java HotSpot(TM) Client VM, Java
Type in expressions to have them evaluated.
:help for more information.
如果你看到scala提示符,那么恭喜你,说明Scala安装成功了。
第二步:学习使用Scala解释器(interpreter)
Scala也算是解释性语言,所以你可以直接与解释器交互。
scala& 1 + 3
res0: Int = 4
直接输入 1 + 3 ,返回res0: Int = 4
res0表示变量名, Int表示类型, 4是值。
Scala的类型定义在冒号后面,和java放在前面不同,和UML类图的属性定义方式一样。
Scala是强类型语言,必须要定义类型,但Scala编译器足够聪明,他能够根据你的值帮你定义变量的类型。
这里res0是个变量名,所以你可以接下来再使用。
scala& res0 * 3
res1: Int = 12
解释器又给了一个变量res1。
Scala的所有变量都是对象,所有操作都是方法。
所以*也是方法,你可以这样调用:
scala& res0.*(res1)
res2: Int = 48
这个和java很不同,java的int不是对象。
是不是有点绕进去了,那么来个hello world宣告第二步结束。
scala& println("Hello World!")
Hello World!
这个println是个方法,因为Scala有预定义导入一些类,所以可以直接使用。
因为Scala更新很快,每个版本的Scala的解释器可能都有一些不同,所以如果返回的变量名或有其他有一点不一样,请不要太奇怪。
第三步: 定义变量
写程序最入门就是定义变量和方法,前面的变量由Scala解释器自动定义了,这一步自己定义变量。
Scala有两种类型的变量,val
变量的值只能初始化一次,再次赋值就发生错误,var就和java的变量相同,可以随时修改。
是函数式编程的风格,变量一旦赋值就不要再做修改,从程序上将有很多好处,但有时候做起来会比较绕。
scala& val msg = "Hello World!"
java.lang.String = Hello World!
scala& msg = "Hello JavaEye"
&console&:5:
error: reassignment to val
msg = "Hello JavaEye"
Scala是强类型语言,每个变量都需要类型。但如果你赋给变量的有足够明细的类型提示,那么编译器会帮你把类型加上去。
把刚才的msg打印出来
scala& println(msg)
Hello World!
再来看看var
,比较好理解。
scala& var greeting: String = "Hello World!"
greeting: String = Hello World!
scala& println(greeting)
Hello World!
scala& greeting = "Hello JavaEye!"
greeting: String = Hello JavaEye!
scala& println(greeting)
Hello JavaEye!
记住,Scala有两种变量标识,和java不一样。
第四步: 定义一些方法
以前程序就是变量和方法组成吧,所以变量和方法是最基础的东西。
我们定义一个取最大值的方法max
scala& def max(x: Int, y: Int): Int = if(x & y) y else x
max: (Int,Int)Int
定义变量用val和var,定义方法用def
这个max方法有方法参数,返回值类型,方法体。麻雀虽小,五脏俱全了。
Scala的变量表示是变量名: 类型
,这一点和java甚至其他语言都很不同,和UML风格比较接近。
调用方法很简单:
scala& max(3,8)
res9: Int = 8
Scala中方法也是一个类型,或者说是一个值,成为First Class。
所以可以把max看成是个变量名,(Int,Int)Int是它的类型。他可以作为参数传递,也可以赋值给其他变量。
scala& val m = max _
m: (Int, Int) =& Int = &function&
将max赋值给m, 请注意max后面带的下划线,不要忘记写了。
scala& m(1,3)
res11: Int = 3
在初学的时候就讲这个好像有点急进了,不太容易理解,不过没关系,先了解一下总比看到后莫名其妙好。
OK,本篇到此结束。
将介绍循环和数组
浏览: 152663 次
来自: 上海
如果用maven管理jar包。记得iText2.X和 iTex ...
都2017年了,还没写完?
都2016年年底了,还没写完吗?
好东西,给楼主赞一个
都2016年了,还没写完?19293人阅读
SCALA学习笔记(一)
获取变量的值是一个耗时的工作时,可以考虑使用lazy var.
lazy val forLater = someTimeConsumingOperation()
scala& val first :: rest = List(1, 2, 3)
first: Int = 1
rest: List[Int] = List(2, 3)
“=”并不只是用来分割函数签名和函数体的,它的另一个作用是告诉编译器是否对函数的返回值进行类型推断!如果省去=,则认为函数是没有返回值的!
scala& def myFirstMethod() = { “exciting times ahead” }
myFirstMethod: ()java.lang.String
scala& def myFirstMethod(){ “exciting times ahead” }
myFirstMethod: ()Unit
注:和本文的其他部分不同,该章节总结自《Learning Scala》一书:Methods and Operators一节,因为《Scala In Action》一书没有集中对这个知识点的讲解
通常,scala和其他大多数的语言一样,对方法的调用使用是:infix dot notation格式,我们可以叫“小数点中辍格式”,也就是对象和方法名中间以“小数点”做中缀的方式:
&class instance&.&method&[(&parameters&)]
与此同时,scala还提供了另外一种方法调用方式:infix operator notation格式,我们可以叫“操作符中辍格式”,也就是把方法名当做一种操作符,使用对象 方法名 参数中间以空格分隔的方式:
&object& &method& &parameter&
这我们思考一下为什么会出现这种样式的方法调用,应该说这是用于引入了“操作符做方法名”而产生的一种自然需要!实际上,scala中允许使用操作符做方法名基本上与C++中的操作符重载是一样的!
scala& val d = 65.642
d: Double = 65.642
scala& d.round
res13: Long = 66
scala& d.floor
res14: Double = 65.0
scala& d.compare(18.0)
res15: Int = 1
//对于Double类型,"+"是一个方法名。
scala& d.+(2.721)
res16: Double = 68.363
很显然,当我们引入了操作符重载之后,如果再使用“对象.方法名(参数)”的方式调用方法会看上去非常古怪,也就是这里的d.+(2.721),此时就是使用infix operator notation样式的合适场所!
当然,这种调用样式并不是一定要使用在以操作符为方法名的方法上,如果你习惯,也可以使用在普通方法上。
函数字面量:FUNCTION LITERALS
In Scala you can also pass a function as a parameter to another function, and most of the time in those cases I provide an inline definition of the function. This passing of functions as a parameter is sometimes loosely called closure (passing a function isn’t always you’ll look into that in chapter 4). Scala provides a shorthand way to create a function in which you write only the function body, called function literals.
以下几个示例中,大括号里面的部分都是函数字面量,
//花括号中的部分是一个标准的函数字面量
scala& evenNumbers.foldLeft(0) { (a: Int, b:Int) =& a + b }
scala& evenNumbers.foldLeft(0) { (a, b) =& a + b }
scala& evenNumbers.foldLeft(0) { _ + _ }
在scala里, 一个下划线代表一个参数!
闭包:Closure
A closure is any function that closes over the environment in which it’s defined. For example, closure will keep track of any variable changes outside the function that are being referred to inside the function.
def breakable(op: =& Unit) { … }
What’s this op: =& Unit? The special right arrow (=&) lets Scala know that the breakable function expects a function as a parameter. The right side of the =& defines the return type of the function—in this case it’s Unit (similar to Java void)—and op is the name of the parameter.
Because you haven’t specified anything on the left side of the arrow, it means that the function you’re expecting as a parameter doesn’t take any parameter for itself.
如果我们需要的传入参数是一个代参数且有返回值的函数呢? 这样的函数作参数应该如何描述呢?
def foldLeft(initialValue: Int, operator: (Int, Int) =& Int)= { … }
让我们这样来理解吧:既然对于函数式编程语言来说,函数是第一位(first class)的,它可以像其他数据类型一样被使用,那么当它作为函数的参数时,我们需要约定一个语法来描述这个”参数”(实际上是一个函数)的”类型”(实际上应该是这个函数的”元信息“),那么对于一个函数来说,它的”类型“应该怎样去描述呢?从语言的设计者角度来考虑的话,那当然最合理的描述方式是:陈述出这个函数的参数类型和它的返回值类型!这也正是operator: (Int, Int) =& Int)所做的!简单明了,合情合理!
Array与Array的基本操作
scala& val array = new Array[String](3)
array: Array[String] = Array(null, null, null)
scala& array(0) = "This"
scala& array(1) = "is"
scala& array(2) = "mutable"
对于给数组赋值的语句:array(0) = “This”,这里要说明的是:不同于java中的array[0] = “This” 在scala中,[]永远是用来制定参数类型的!
迭代Array的操作是非常简单的,我们只需要使用它的foreach方法,同时传递一个函数字面量即可。下面典型的例子是在迭代main函数的args参数列表:
scala& array.foreach(println)
Array的基本操作
关于Array的基本操作应该参考scala.collection.mutable.ArrayLike这个trait,然而有趣是的,Array并没有实现这个trait. 这是非常有意思的。
关这个问题的答案是Predef! Scala的Predef会隐式地将一个Array转成一个scala.collection.mutable
.ArrayOps. 而ArrayOps 是ArrayLike的一个子类。
val files = new java.io.File(".").listFiles
for(file &- files) {
val filename = file.getName
if(fileName.endsWith(".scala")) println(file)
The only thing that looks different from for loops in Java or C# is the expression file &- files. In Scala this is called a generator, and the job of a generator is to iterate through a collection.
scala& val aList = List(1, 2, 3)
aList: List[Int] = List(1, 2, 3)
scala& val bList = List(4, 5, 6)
bList: List[Int] = List(4, 5, 6)
scala& for { a &- aL b &- bList } println(a + b)
scala& val result = for { a &- aL b &- bList } yield a + b
result: List[Int] = List(5, 6, 7, 6, 7, 8, 7, 8, 9)
scala& for(r &- result) println(r)
注:for语句的花括号{}并不是必须的,你完全可以使用().
模式匹配:Pattern Matching
模式匹配,示例一:
ordinal(args(0).toInt)
def ordinal(number:Int) = number match {
case 1 =& println("1st")
case 2 =& println("2nd")
case 3 =& println("3rd")
case 4 =& println("4th")
case 5 =& println("5th")
case 6 =& println("6th")
case 7 =& println("7th")
case 8 =& println("8th")
case 9 =& println("9th")
case 10 =& println("10th")
case _ =& println("Cannot do beyond 10")
case _ to match everything else.
模式匹配,示例二:
在下面的这个例子中展示了scala一些内置的预定义的Pattern,专门应用于case上的,例如下面例子中的:f,s, rest
scala& List(1, 2, 3, 4) match {
case f :: s :: rest =& List(f, s)
case _ =& Nil
res7: List[Int] = List(1, 2)
模式匹配,示例三:
val suffixes = List("th", "st", "nd", "rd", "th", "th", "th","th", "th","th");
println(ordinal(args(0).toInt))
def ordinal(number:Int) = number match {
case tenTo20 if 10 to 20 contains tenTo20 =& number + "th"
case rest =& rest + suffixes(number % 10)
What val and var do is define a field and a getter for that field, and in the case of var an additional setter method is also created. When both of them are missing, they’re treated as private instance values, not accessible to anyone outside the class.
对于Class的field的修饰符有如下约定:
使用var声明field,则该field将同时拥有getter和setter
scala& class MongoClient(var host:String, var port:Int)
使用val声明field,则该field只有getter。这意味着在初始化之后,你将无法再修改它的值。
scala& class MongoClient(val host:String, val port:Int)
如果没有任何修饰符,则该field是完全私有的。
scala& class MongoClient(host:String, port:Int)
Getter和Setter
如何显示地定义一个字段的getter和setter
在Scala里,如果需要手动地为一个字段添加getter和setter规则是这样的:
字段名应以_在前缀,如_age
getter是一个function,其命名在字段名上去除_即可,如def age=_age
setter的定义看似有些奇怪,其实只是一些约定,熟悉以后就可以了。setter的命名是在去除字段名上去除前缀,然后在后面添加”=”后缀,对是”_=”!然后再接参数列表,再之后就和普通的函数定义没有区别了!
我们再来看这个例子:
class Person(var firstName:String, var lastName:String, private var _age:Int) {
def age = _age //age是一个function,因为没有参数,所以参数列表为空,它是为私有字段_age定义的getter
def age_=(newAge: Int) = _age = newAge //“age_=”是setter的函数名!这里如果写成def age_=(newAge: Int) = {_age = newAge}看上去就不奇怪了。
之后,我们可以这样使用:
val p = new Person("Nima", "Raychaudhuri", 2)
The assignment p.age = 3 could be replaced by p.age_=(3). When Scala encounters an assignment like x = e, it checks whether there’s any method defined like x_= and if so, it invokes the method.
Primary Constructor声明的字段其读写属性是如何规定的?
让我们通过一个完整的例子来看一下:
scala& class Person(val firstName:String, var lastName:String, gender:String)
defined class Person
scala& val p=new Person("Jim","White","male")
p: Person = Person@c80472c
scala& p.firstName
res2: String = Jim
scala& p.lastName
res3: String = White
scala& p.gender
&console&:10: error: value gender is not a member of Person
scala& p.firstName="Tom"
&console&:9: error: reassignment to val
p.firstName="Tom"
scala& p.lastName="Green"
p.lastName: String = Green
scala& p.gender="female"
&console&:12: error: value gender is not a member of Person
val $ires6 = p.gender
&console&:9: error: value gender is not a member of Person
p.gender="female"
如果是var:生成getter和setter
如果是val:只生成getter
如果没有变量修饰符:没有getter和setter,等同于private.
但是注意对于Case Class,则稍有不同!Case Class对于通过Primary Constructor声明的字段自动添加val修饰,使之变为只读的。
scala& case class Person2(firstName:String)
defined class Person2
scala& val p=Person2("Jim")
p: Person2 = Person2(Jim)
scala& p.firstName
res5: String = Jim
scala& p.firstName="Tom"
&console&:10: error: reassignment to val
p.firstName="Tom"
主构造函数:Primary Constructor
scala的主构造函数指的是在定义Class时声明的那个函数!简单的例子:
&scala& class MongoClient(val host:String, val port:Int)
对于这个class的定义,实际上它也是同时声明了一个构造函数:this(val host:String, val port:Int), 它就是所谓的主构造函数!
关于构造函数重载
在scala中,构造函数的重载和普通函数的重载是基本一样的,区别只是构造函数使用this关键字指代!当然,也不能指定返回值。
对于重载构造函数:它的第一个语句必须是调用另外一个重载的构造函数或者是主构造函数!当然除了主构造函数以外!这个表述如果再深入地一想,那么我们就可以想到:所有的构造函数在一开始就会首先调用主函数!!这也是为什么:scala对写在Class内的零星的脚本和代码片段的处理是通过移到主构造函数内去执行的原因!
class MongoClient(val host:String, val port:Int) {
def this() = {
val defaultHost = "127.0.0.1"
val defaultPort = 27017
this(defaultHost, defaultPort)
在上面的代码汇编出错,因为它的第一行并不是在调用另外一个构造函数!
关于Scala的脚本特性
这是一个明显不同于java的地方,我们来看一个Class:
class MyScript(host:String) {
require(host != null, "Have to provide host name")
if(host == "127.0.0.1") println("host = localhost")
else println("host = " + host)
如果这是一个java类,则这显然是不合乎语法的。Scala的脚本特性体现在:*在一个类里,你可以随意的写一些脚本,或者说是代码片段更加形象,这些脚本会在对象实例化时被执行。
两种风格,
package com {
package scalainaction {
package mongo {
import com.mongodb.Mongo
class MongoClient(val host:String, val port:Int) {
require(host != null, "You have to provide a host name")
private val underlying = new Mongo(host, port)
def this() = this("127.0.0.1", 27017)
package com.scalainaction.mongo {
import com.mongodb.Mongo
class MongoClient(val host:String, val port:Int) {
require(host != null, "You have to provide a host name")
private val underlying = new Mongo(host, port)
def this() = this("127.0.0.1", 27017)
每当你在类前声明:package com.scalainaction.mongo时,则package中的对应代码会自动执行!
scala的package机制有意思的一点是:包的结构并不需要对应映射和class的文件结构上,当一个package被编译时,编译器会根据package的声明生成对应的文件结构!
import com.mongodb._
Here’s another use for _, and in this context it means you’re importing all the classes
under the com.mongodb package.
并且你可以在任何地方使用import:
scala& val randomValue = {
import scala.util.Random
new Random().nextInt
randomValue: Int =
下面是一种类似java中的static import的方式,导入一个类的所有方法:
scala& import java.lang.System._
import java.lang.System._
scala& nanoTime
res0: Long = 7441000
scala中的import还有另外一个方便的特性:在导入时它可以重命名类或包,这样会增加可读性,比如下面的这个例子:
import java.util.Date
import java.sql.{Date =& SqlDate}
import RichConsole._
val now = new Date
val sqlDate = new SqlDate(now.getTime)
p(sqlDate)
Object对象
基于“纯OO”的理念,scala里没有static关键字的:一切皆对象!
但是为了能实现“全局唯一”的需要,scala支持一种叫做singleton object的对象,也就是限定一个类的实例只有唯一一个的机制。
object RichConsole {
def p(x: Any) = println(x)
scala& RichConsole.p("rich console")
rich console
上述代码定义了一个object:RichConsole,对于它的调用和与java里调用static的字段和方法是极其类似的!
像使用function一样使用object.
Scala provides syntactic sugar that allows you to use objects as function calls. Scala achieves this by translating these calls into the apply method, which matches the given parameters defined in the object or class.
实际上,这是一种“约定”,只要你的object中定义了一个apply方法,你是可以直接使用object的名字作为函数名后接与 apply方法对应的参数就可以实现对这个apply方法的调用!我们看下面的这个例子:
scala& object A {
| def apply(s:String)=println(s)
defined object A
scala& A("SDFSDF")
这个语法机制多用于实例化一个对象,使得object成为一个工厂,我们接着看下面这个话题:
将object类型作为“工厂”Factory来使用
一个典型的工厂类(实际上我们这里指的是简单工厂(静态工厂)模式),通常是以static的工厂方法来create对象的,比如:
Factory.createObject("objectA");
让我们来看一下scala中通过object来实现的工厂类:
class DB private(val underlying: MongoDB) {
private def collection(name: String) = underlying.getCollection(name)
def localeAwareReadOnlyCollection(name: String) =
new DBCollection(collection(name)) with Memoizer with LocaleAware
def readOnlyCollection(name: String) =
new DBCollection(collection(name)) with Memoizer
def administrableCollection(name: String) =
new DBCollection(collection(name)) with Administrable with Memoizer
def updatableCollection(name: String) =
new DBCollection(collection(name)) with Updatable with Memoizer
def collectionNames =
for(name &- new JSetWrapper(underlying.getCollectionNames)) yield name
object DB {
def apply(underlying: MongDB) = new DB(underlying)
DB(underlying.getDB(name))
像上面提到的,既然这是一个object类型,那么调用工厂方法apply的方式就应该是这样:DB.apply(myUnderlying)但是scala在这里有一个语法糖,它允许我们像使用函数一样使用object!所以上面的调用也可以写成这样:DB(myUnderlying)
让我们再来看另外一个更加明显和清晰的例子,这是scala里一个典型简单工厂(静态工厂方法)模式的实现:
abstract class Role { def canAccess(page: String): Boolean }
class Root extends Role {
override def canAccess(page:String) = true
class SuperAnalyst extends Role {
override def canAccess(page:String) = page != "Admin"
class Analyst extends Role {
override def canAccess(page:String) = false }
object Role {
def apply(roleName:String) = roleName match {
case "root" =& new Root
case "superAnalyst" =& new SuperAnalyst
case "analyst" =& new Analyst
val root = Role("root")
val analyst = Role("analyst")
A trait is like an abstract class meant to be added to other classes as a mixin.You can also view a trait as an interface with implemented methods.
在Scala里,Trait像一个抽象类,它用于作为一种“mixin”混入到其他类中!你也可以把它看作是带有方法实现的接口(Interface),另一方面,trait区别于抽象类的地方在于:抽象类可以有构造函数,且构造函数可以有参数!但是对于trait,是没有带参数的构造函数的!所以说它更像是“有实现方法的接口”。trait不同于接口和抽象类的另一个地方是:它是不仅可以有抽象方法,还可以有抽象字段!
memoization:In computing, memoization is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again.
Trait和多继承
由于一个类可以混入多个Trait! 这很明显地让人联想到“多继承”机制,以及由此带来的问题!
这我们看下面这个例子:
Class UpdatableCollection
extends DBCollection(collection(name)) with Updatable
以下是类继承关系:
在这个类继承关系下,readonly的方法被Updatble和DBCollection两个条线路继承和改写,这样,对于UpdatableCollection来说就需要一种规则来确定继承路线,解决歧义性问题,scala使用的规则叫:class linearization这个原则简单表述为:右侧优先,深度优先!
上面这个例子,在UpdatableCollection的类声明中,Updatable出现在最右侧,所以UpdatableCollection会优先继承Updatable里关于ReadOnly的实现,后续再出现相同的方法时就忽略掉。
Trait的“堆栈化”(叠加)特性
但是我们也要看到Trait这种类似多继承的特性对修改已存在组件的行为和构建可重用组件方面是有很大帮助的!我们只需要重新设计一个Trait,就可以轻松地把已有的Trait的行为替换掉,从这一点上我们也可以理解为什么在确定继承路线时,scala总是先从最右边开始了!这很像是一个堆栈!声明的每一个trait从左向右依次入栈,在解析时依次出栈,从最右则开始解析。
Case Class
以这样一段代码为例:
scala& case class Person(firstName:String, lastName:String)
defined class Person
当我们声明一个Case Class的时候,编译器会自动完成以下动作:
scala prefixes all the parameters with val, and that will make them public value. But remember that you still never acces you always access through accessors.
对于Case Class,它的主构造函数的所有参数会被自动限定为val,也就意味着这个字段是外部可读的。 这与普通的Class主构造函数不同。
对于普通的Class:
scala& class MongoClient(host:String, port:Int)
如果没有任何修饰符,则该field是完全私有的,既无getter也无setter,只在类的内部可读。
Both equals and hashCode are implemented for you based on the given parameters.The compiler implements the toString method that returns the class name and its parameters.
Every case class has a method named copy that allows you to easily create a modified copy of the class’s instance. You’ll learn about this later in this chapter.
A companion object is created with the appropriate apply method, which takes the same arguments as declared in the class.
The compiler adds a method called unapply, which allows the class name to be used as an extractor for pattern matching (more on this later).
下面一组case class:
sealed trait QueryOption
case object NoOption extends QueryOption
case class Sort(sorting: DBObject, anotherOption: QueryOption) extends QueryOption
case class Skip(number: Int, anotherOption: QueryOption) extends QueryOption
case class Limit(limit: Int, anotherOption: QueryOption) extends QueryOption
关于case class生成的companion object
case class Person(firstName:String, lastName: String)
当我们声明上面这样一个case class的时候,我们知道scala会为case class自动生成一个companion object, 如果还原这个companion object的代码,应该是这样的:
object Person {
def apply(firstName:String, lastName:String) = {
new Person(firstName, lastName)
def unapply(p:Person): Option[(String, String)] =
Some((p.firstName, p.lastName))
对于apply方法不必再多介绍了,它会在创建Persion Class实例时调用。
对于unapply方法,它会在case class的模式匹配时使用!这个方法主要是把一个case class实例的进行“拆解”(unwrap)返回它的参数,以便进行模式匹配时使用!这大概的起名为unapply的原因吧。
命名参数 Named Arguments
先看例子:
scala& case class Person(firstName:String,lastName:String)
defined class Person
scala& val p = Person(lastName="lastname",firstName = "firstname")
p: Person = Person(firstname,lastname)
scala& println(p.lastName)
有时候,人们可能回错误地传递了参数,特别是当多个参数是同一类型时,这样编译器不能帮助我们检查出错误的。比如像上面的这个例子,如果我们在实例化p时错误的写成了val p = Person("lastname","firstname"),这种错误是无法依靠编译器来帮助我们发现的,scala中提供的“命名参数”机制可以帮助我们写出更加易读的代码,同时错误也更少!上面示例代码中,即使我们把参数的顺序都弄错了,但是由于传递的“实参”已被声明是指定给某个“形参”的,所以就不会出现任何错误和疏漏了!
在使用命名参数时,如果参数命名不匹配,编译器会报错,但是有这样一种case,如果一个方法,父类对参数有一个命名,子类在重写这个方法时把参数名也改了,那么在使用命名参数时应该使用哪一个?scala的原则是看实例化出来的对象是什么类型,如果是子类型,应该使用子类方法上的参数命名,如果这个对象被强制转换为了父类,则使用父类方法中的参数命名,看下面这个例子:
scala& trait Person { def grade(years: Int): String }
defined trait Person
scala& class SalesPerson extends Person { def grade(yrs: Int) = "Senior" }
defined class SalesPerson
scala& val s = new SalesPerson
s: SalesPerson = SalesPerson@42a6cdf5
scala& s.grade(yrs=1)
res17: java.lang.String = Senior
scala& s.grade(years=1)
&console&:12: error: not found: value years
s.grade(years=1)
由于s的类型是SalesPerson,所以使用yrs命名参数1是OK的,使用Persion的years命名就报错!除非之前你把s强制转换成了Persion!
类成员修饰符
关于public:
By default, when you don’t specify any modifier, everything is public. Scala doesn’t provide any modifier to mark members as public.
关于abstract override
The override modifier can be combined with an
abstract modifier, and the combination is allowed only for members of traits. This
modifier means that the member in question must be mixed with a class that provides
the concrete implementation.
Scala的类体系结构
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:3517461次
积分:28913
积分:28913
排名:第174名
原创:274篇
评论:593条
架构师,CSDN博客专家,目前正从事大数据领域的研究和开发工作,对企业级应用架构、分布式存储、SaaS和领域驱动设计有丰富的实践经验,热衷函数式编程,喜欢摄影和旅行。
文章:26篇
阅读:112364
文章:16篇
阅读:326459
文章:35篇
阅读:386534
阅读:486387
(2)(3)(1)(4)(5)(5)(1)(1)(3)(6)(4)(1)(2)(1)(4)(2)(1)(2)(3)(1)(3)(2)(6)(10)(5)(3)(2)(2)(3)(4)(1)(4)(4)(2)(1)(1)(2)(1)(1)(4)(1)(2)(3)(1)(2)(5)(5)(5)(3)(2)(3)(10)(4)(4)(8)(5)(6)(1)(10)(1)(2)(6)(10)(4)(2)(10)(5)(11)(20)(3)(3)(1)(2)(1)(2)(2)(7)(1)(3)(2)

我要回帖

更多关于 浙江七选三技术好学吗 的文章

 

随机推荐