Scala 集成开发环境配置
很多人说Scala的IDE推荐用intellij idea,eclipse对scala插件的支持相对而言没有idea好。这里我保留意见。不过idea确实是一款不错的IDE,但是伟大的祖国的墙让idea的scala插件在线下载变得遥不可及,即使我这个上海50M电信宽带用户也是一样泪流满面。
所以,scala插件去idea插件官网直接下载,用迅雷下很快。地址如下:
需要注意的是,你要选择对应你idea版本的插件。
http://plugins.jetbrains.com/plugin/1347-scala
接下来讲下载好的scala-intellij-bin-2016.2.1.zip插件从本地安装上去。
【File】-【Settings】-【Plugins】-【Install plugin from disk】
点击重启。
现在发现新建项目已经有scala了。
这时候你就可以新建Scala类文件了。
但是有可能你会发现插件刚刚装好,也重启idea了,但是new的菜单里没有Scala Class。这时候,如果你直接用File项强制创建一个*.scala文件,打开这个scala文件时,编辑器会提示“No scala SDK in Module”。
原因是我们本地安装的Scala SDK没有配置到Idea的IDE环境中。你可以点击这个“No scala SDK in Module”一行提示右边的超链接,打开一个导入SDK的的对话框,选择你安装Scala SDK的本地目录即可。之后你会发现再次打开这个scala文件这个提示就没有了,并且新建菜单中也有Scala class了。由于我已经配好,所以没截图,大家自己试试吧。
对于一个更习惯于eclipse一脉各类IDE的人来说,scala IDE(eclipse的衍生品)更适合我。而且一些地方也没有idea粉说得那么不堪。
http://scala-ide.org/
免安装、插件已经都配好,直接用即可。
Scala核心基本概念
上一篇我们直接介绍了一些基本的操作作为开篇,以帮助大家有个直观的印象。本篇着重将scala,这门基于JVM的、完全面向对象的、函数式编程语言的一些基本的、核心的概念做一个介绍。
Scala相较于Java一个最显著的不同是,Scala是真正的函数式编程语言。所以我在此深度递归式地发出“四问“。引出四个基本概念:
什么是函数式编程?
只用纯函数来编程。
什么叫纯函数(Pure Funcation)?(也称函数的纯粹性)
没有副作用的函数。
什么叫做副作用(Side Effect)?
副作用是状态的变化
什么是状态的变化(mutation)?
例如:
修改全局变量
抛出异常
IO读写
调用有副作用的函数
也就是说在凡是存在对全局变量修改、会抛异常的、设计IO读写操作的函数调用都不能算作是函数式编程。
函数式编程是一种计算范式,感性地说,函数式编程将计算过程当做是一种数学函数计算求值的过程。避免了改变状态和可变的数据。
从数学函数的角度,我们引入一个概念:
引用透明性,(Referential Transparency),相同的输入总是能够得到相同的输出。
如果f(x)的参数x和函数体都是引用透明的,那么函数f是纯函数。
object Blog2 {
def main(args: Array[String]): Unit = {
// println("Eclipse for Scala is OK");
fn2();
}
def fn2():Unit={
val s1=new StringBuilder("Happy");
println("s1 is",s1);
val s2=s1.append("BKs");
println("s2 is",s2);
val s3=s1.append("BKs");
println("At last, s1 is",s1);
println("At last, s2 is",s2);
println("At last, s3 is",s3);
}
}
即对于相同的一个输入,append方法的返回前后是不一样的。append方法违反了引用透明性。
怎么样确保我们的程序是引用透明的呢?这里引入另一个概念——不变形(immutablity):
为了获得引用透明性,任何值不能发生变化。
三大重要概念或观点
对于函数式编程而言,有三个非常重要的概念,或者说观点:
(1)函数是第一等公民(First-Class Function)
一切都是计算
函数式编程中一切都是表达式,变量是表达式、函数也是表达式
你可以把函数当做一个参数传给另一个函数,也可以吧一个函数作为另一个函数的返回值返回出来;你可以在一个函数体里面定义一个函数。
在编写函数式编程的时候,你用到变量的地方同样可以使用函数。
(2)高阶函数(Higher Order Function)
如果一个函数的输入参数或输出返回值是是另一个函数,这样的函数称为高阶函数。
(3)闭包(Closure)
这是函数式编程的一个非常重要的概念,本文暂不介绍,在本系列的后面会有专门的文章展开介绍。
Scala表达式的求值策略
严格求值(Call by Value):
非严格求值(Call by Name):
惰性求值(Lazy Evaluation):当定义一个表达式的时候,表达式的值不会立即被计算求值,只有当第一次调用这个表达式的时候才回去求值。
递归函数(Recursive Function)
递归在函数式编程中有举足轻重的地位,因为在函数式编程中是没有循环语句的。所有的循环都是用递归来实现的。
但是众所周知,递归有一个缺点——性能问题:递归的层数一深入,容易堆栈溢出。
调优递归,有一种技术叫做尾递归(Tail Recursion)。这里先给个直观的理解,就是我们把函数体内递归调用的语句放在整个函数体的尾部,使得递归返回时正好是上层函数体的尾部,所以从某种程度上说无须保存上层函数体的上下文环境,也就不存在因为递归深度的加深,各层上下文环境保存积累而导致的内存溢出。这部分我将在后续文章介绍函数的时候再做展开。
总结,最后把这个图中的关键词看看自己是否已经了然于心。
上一篇的补充
关于入门的知识,上一篇快速入门一些基本的概念没有罗列,这里做个入门补充。
变量声明
Scala的变量声明有不同的语法,它们可以被定义为值,即,常量或变量。下面是使用var关键字来定义一个变量的语法:
var myVar : String = "happybks"
在这里,myVar使用关键字var声明。这意味着它是一个可以改变值的变量,被称为可变变量。下面是使用val关键字来定义变量的语法:
val myVal : String = "happybks"
myVal =myVal +", yeah"
这里,myVal是使用关键字val声明。这意味着,它是不能改变的变量,这是所谓的不可变变量。
当分配一个初始值给一个变量,Scala编译器可以计算出根据分配给它的值的变量类型。这就是所谓的变量类型推断。
//Scala在声明变量时可以声明变量的类型,但是约束类型之后必须初始化值,否则报错;初始化或赋值的类型不对也会报错。
var myVar:Int=10;
var myVar2:String="Hello, Scala!";
//myVar2=2;//Error:type mismatch;
//var myVar3:Int;//ERROR:only classes can have declared but undefined members
//变量无论是var还是val,都必须初始化;var之后可以赋值与初始化时同类型性的值,但val不可以再修改变量值
//如果生命变量没有指定类型,var变量初始化之后不可以赋其他类型的值
var x2=0;
//x2="happybks";// Error: type mismatch;
函数的编写:
这里写了一个求最大公约数的函数(当然函数式编程最好用尾递归)。我这里这样用while是想说明,scala不仅是一门纯粹的函数式语言,也同样支持一般主流面向对象高级语言的语法糖。
def gcd(x: Long, y: Long): Long = {
var a = x
var b = y
while (a != 0) {
val temp = a
a = b % a
b = temp
}
b
}