scala 返回值中返回值是string 类型的方法 怎么写

Scala类型推导_東海陳光劍_新浪博客
Scala类型推导
Scala类型推导
什么是静态类型?为什么它们很有用?
根据Picrce的说法:“类型系统是一个可以根据代码段计算出来的值对它们进行分类,然后通过语法的手段来自动检测程序错误的系统。”
类型可以让你表示函数的域和值域。例如,在数学里,我们经常看到下面的函数:
这个定义告诉我们函数”f”的作用是把实数集里的数映射到自然集里。
抽象地说,这才是具体意义上的类型。类型系统给了我们一些表示这些集合的更强大的方式。
有了这些类型标识,编译器现在可以 静态地(在编译期)判断这个程序是正确的。
换句话说,如果一个值(在运行期)不能够满足程序里的限制条件的话,那么在编译期就会出错。
通常来说,类型检测器(typechecker)只能够保证不正确的的程序不能通过编译。但是,它不能够保证所有正确的程序都能通过编译。
由于类型系统的表达能力不断增加,使得我们能够生成出更加可靠的代码,因为它使得我们能够控制程序上的不可变,即是是程序还没有运行的情况下(在类型上限制bug的出现)。学术界一直在努力突破类型系统的表达能力的极限,包含值相关的类型。
注意,所有的类型信息都会在编译期擦除。后面不再需要。这个被称为类型擦除。比如,Java里面的泛型的实现.
Scala中的类型
Scala强大的类型系统让我们可以使用更具有表现力的表达式。一些主要的特点如下:
支持参数多态,泛型编程
支持(局部)类型推导,这就是你为什么不需要写val i: Int = 12: Int
支持存在向量(existential quantification),给一些没有名称的类型定义一些操作
支持视图。 给定的值从一个类型到其他类型的“可转换性”
多态可以用来编写泛型代码(用于处理不同类型的值),并且不会减少静态类型的表达能力。
例如,没有参数多态的话,一个泛型的列表数据结构通常会是下面这样的写法(在Java还没有泛型的时候,确实是这样的):
:: 1 :: "bar" :: "foo" ::
Nil res5: List[Any] =
List(2, 1, bar, foo)
这样的话,我们就不能够恢复每个元素的类型信息。
scala& res5.head
res6: Any = 2
这样一来,我们的应用里会包含一系列的类型转换(“asInstanceOf[]“),代码会缺少类型安全(因为他们都是动态类型的)。
多态是通过指定类型变量来达到的。
scala& def drop1[A
](l: List[A]) = l.tail drop1:
[A](l: List[A])List[A]
scala& drop1(List(1,2,3)) res1: List[Int] = List(2,
多态是scala里的一等公民
简单来说,这意味着有一些你想在Scala里表达的类型概念会显得“太过于泛型”,从而导致编译器无法理解。所有的类型变量在运行期必须是确定的。
对于静态类型的一个比较常见的缺陷就是有太多的类型语法。Scala提供了类型推导来解决这个问题。
函数式语言里比较经典的类型推导的方法是 Hindlry-Milner,并且它是在ML里首先使用的。
Scala的类型推导有一点点不同,不过思想上是一致的:推导所有的约束条件,然后统一到一个类型上。
在Scala里,例如,你不能这样写:
scala& { x =& x }
: error: missing parameter type { x =& x }
但是在OCaml里,你可以:
# fun x -&;
- : 'a -& 'a =
在Scala里,所有的类型推导都是局部的。Scala一次只考虑一个表达式。例如:
scala& def id[T
](x: T) = x id: [T](x:
T)T scala& val x = id(322) x: Int = 322
scala& val x = id("hey") x: java.lang.String = hey
scala& val x = id(Array(1,2,3,4)) x: Array[Int] =
Array(1, 2, 3, 4)
在这里,类型都被隐藏了。Scala编译器自动推导参数的类型。注意我们也没有必要显示指定返回值的类型了。
Scala的类型系统需要把类的继承关系和多态结合起来。类的继承使得类之间存在父子的关系。当把面向对象和多态结合在一起时,一个核心的问题就出
来了:如果T'是T的子类,那么Container[T']是不是Container[T]的子类呢?Variance注释允许你在类继承和多态类型之间
表达下面的这些关系:
Scala中的标记
covariant(协变)
C[T’]是C[T]的子类
contravariant(逆变)
C[T]是C[T’]子类
invariant(不变)
C[T]和C[T’]不相关
子类关系的真正意思是:对于一个给定的类型T,如果T’是它的子类,那么T’可以代替T吗?
scala& class
Contravariant[-A] defined class Contravariant
scala& val cv: Contravariant[String] =
new Contravariant[AnyRef] cv: Contravariant[AnyRef] =
Contravariant@49fa7ba scala& val fail:
Contravariant[AnyRef] = new
Contravariant[String] :6: error: type
found : Contravariant[String] required:
Contravariant[AnyRef] val fail: Contravariant[AnyRef] =
new Contravariant[String]
量化(Quantification)
有时候你不需要给一个类型变量以名称,例如
scala& def count[A
](l: List[A]) = l.size count:
[A](List[A])Int
你可以用“通配符”来替代:
scala& def count(l: List
[_]) = l.size count: (List[_])Int
什么是类型推导
先看个代码:
Map&&span&String
, String&& m =
HashMap&&span&String,
String&&();
是啊, 这简直太长了,我们不禁感叹,这编译器也太愚蠢了.几乎一半字符都是重复的!
针对泛型定义和实例太过繁琐的问题,在java 7 中引入了钻石运算符. 神奇的Coin项目,满足了你的心愿.
于是,你在java 7之后可以这样写了:
Map&&span&String
, String&& m =
new HashMap();
钻石运算符通常用于简化创建带有泛型对象的代码,可以避免运行时
的异常,并且它不再要求程序员在编码时显示书写冗余的类型参数。实际上,编译器在进行词法解析时会自动推导类型,自动为代码进行补全,并且编译的字节码与
以前无异。
当时在提案中,这个问题叫"Improved Type Inference for Generic Instance
Creation",缩写ITIGIX听起来怪怪的,但是为啥叫钻石算法? 世界上, 哪有那么多为什么.
Scala正是因为做了类型推导, 让Coders感觉仿佛在写动态语言的代码.
在Scala中,高阶函数经常传递匿名函数.举个栗子:
一段定义泛型函数的代码
dropWhile[A](list: List[A], f: A
=& Boolean): List[A]
当我们传入一个匿名函数f来调用它,
val mylist
: List[Int] =
List(1,2,3,4,5)
val listDropped = dropWhile( mylist, (x:
Int) =& x &
listDropped的值是List(4,5)
我们用大脑可以轻易判断, 当list: List[A] 中的类型A在mylist声明的时候已经指定了Int, 那么很明显,
在第二个参数中,我们的x也必是Int.
很幸运Scala设计者们早已考虑到这一点,Scala编译器可以推导这种情况.但是你得按照Scala的规范限制来写你的dropWhile函数的签名(柯里化的):
dropWhile( mylist )( f )
dropWhile[A] ( list: List[A]
) ( f: A =& Boolean ) : List[A]
= list match { case Cons(h,t) if f(h)
=& dropWhile(t)(f) case _ =& list
如此而来,我们就可以直接像下面这样使用这个函数了:
val mylist: List
List(1,2,3,4,5)
val droppedList = dropWhile( mylist ) ( x =& x
注意, x参数没有指定Int类型, 因为编译器直接通过mylist的泛型信息Int推导出x的类型也是Int.
类型推导是一门博大的学问,背后有繁冗的理论, 这在编译器设计开发的时候需要解决的问题.
Haskell,ML
局部的(local)、基于流的(flow-based)类型推断
全局化的Hindley-Milner类型推断
在《Programming in
Scala》一书中提到基于流的类型推断有它的局限性,但是对于面向对象的分支类型处理比Hindley-Mlner更加优雅。
基于流的类型推导在偏应用函数场景下,不能对参数类型省略
类型推导算法
类型推导(Type Inference)是现代高级语言中一个越来越常见的特性。其实,这个特性在函数式语言
中早有了广泛应用。而HindleyMilner推导器是所有类型推导器的基础。
关于作者: 陈光剑,江苏东海人, 号行走江湖一剑客,字之剑。程序员,诗人, 作家
http://universsky.github.io/​
東海陳光劍
博客等级:
博客积分:0
博客访问:224,824
关注人气:0
荣誉徽章:1、进入scala:直接输入scala即可
2、退出:输入:quit或者:q都可以
3、输入变量一部分,按Tab键可补全可调用的方法名称
4、从技术上讲Scala并不是一个解释器,实际上是将读取的输入内容迅速的编译成字节码,然后交由Java虚拟机执行,也被称为REPL(读取-计算-打印-循环)
5、声明常量值使用val,如val a=10;(注:使用val定义的变量的值不允许再修改,否则会报error: reassignment to val的错误)
6、var 声明的变量值可改变
7、变量在定义时必须做初始化,否则会报错,而且同一行代码中有多条语句时需用分号;隔开
8、Scala有9种数值类型,Byte、Int、Long、String、Double、Char、Short、Float、Boolean,与Java不同的是Scala不区分值类型与引用类型,因为你可以对一个整型使用toString方法,如1.toString
9、基本数据类型转换:String在操作时可以被隐式转换成StringOps对象,通过StringOps对象给字符串添加了上百种操作,如:"hello".intersect("world")找出两个字符串中共同的字符、toString方法转换成字符串、toInt、toDouble转换成数字等方法
& & 删除某个字符"hello".drop(2)输出llo,删掉了左边两个,dropRight(2)是删掉右边两个
& & "hello".filter(_!='l')输出heo,将l过滤掉了
10、val bulder = new StringBbuilder.append("hello")定义可变字符串
11、Scala运算符号与java不同的是Scala中的运算符是当做方法来使用的,如a+b是a.+(b)的简写
12、调用函数,先引入响应的包,如import scala.math._(_符号类似java中的*,是一个通配符操作)
13、在Scala中允许使用字符串乘以数字,如"abc"*3输出abcabcabc即输出了3遍abc,但是反过来数字乘以字符串是不允许的
14、scala 在线API:http://www.scala-lang.org/api/2.11.7
15、由于Scala中有类型推断的机制,所以定义变量时不用指定类型,如var x=1,如果想显示指定也可以,如var m:String="abc"
16、不同于Java,Scala在如var x,y=10定义变量时x、y都会赋值10,而java中只会给y赋值10
17、如图,x打印结果为Unit,原因在于赋值语句在scala中的返回值为Unit(跟Java中不同)
18、如图,Scala有隐式转化功能,点击7行前的图标可以看到Scala将String隐式转换成了StringOps,即toInt是StringOps的方法,所以在以后用到String时驶入某个方法没有定义,可以看下StringOps里面有没有定义,其实不止String,int、double等也都有对应的RichInt、RichDouble为其提供了很多方法可以调用
19、在Scala中操作符其实调用的都是方法,如1+2是1.+(2)的简写,而且在Scala中如果方法的参数只有1个,可以写成操作符的形式,如1 to 10、1 max 2等等
& & &&在明确了方法调用的接收者的情况下,若方法只有一个参数时,调用的时候就可以省略点及括号。如 &0 to 2&,实际完整调用是 &0.to(2)&。但 &println(2)& 不能写成 &println 10&&,因为未写出方法调用的接收者 Console,所以可以写成 &Console println 10&
阅读(...) 评论()Scala入门初探学习Scala入门初探1. 变量定义Scala有两类变量val和varval:(value)类似于java里面的final变量,一旦初始化就不允许再被赋值;var:(variable) 如同java里的非final变量,可以多次赋值定义变量时,不需要指定变量的具体类型,如:val str = &Hello&,Scala编译器能自动推断出str的类型为String(类型推断),当然有时候为了代码清晰,写成var str:String = &Hello&也是可以的。2. 函数定义
def max(x: Int, y: Int): Int = {
if (x & y)
}如果函数能自动推断返回类型,则返回类型不需要写,如果函数只包含一条语句,则花括号也不需要,如上例max函数可简化为:
def max(x: Int, y: Int) = if (x & y) x else y既不带参数也不返回值的函数,如
Scala&def greet() = println(&Hello,world&)
greet: ()Unitgreet是函数名,空白括号()代表函数无参数,Unit是函数的返回类型,指的是函数没有有效的返回值,类似java的void如果函数没有参数,也可以不写括号
Scala&def greet = println(&Hello,world&)
greet: Unit
scala& def greet:Int = { var t = 2
greet: Int3. 循环Scala不支持i++和++i,必须写成i += 1或者i = i + 1函数字面量(感觉就像是匿名函数),=&左边是参数列表,=&右边是函数体
(x:Int, y:Int) =& x + y
args.foreach((arg:String)=&println(arg))
args.foreach(arg=&println(arg))
args.foreach(println)
---31 类型可推断,不需要指定类型2、3 只有一个参数时,可以去掉括号,甚至省略参数
for(arg &- args)
println(arg)分享到:最近浏览暂无贡献等级扫描二维码关注最代码为好友"/>扫描二维码关注最代码为好友经检测你所在的网络可能存在爬虫,因资源限制,我们只能拒绝你的请求。
如果你是推酷的用户,可以以继续访问使用。
如有疑问,可将IP信息发送到
请求解封。Scala学习笔记1——Scala入门 - 简书
<div class="fixed-btn note-fixed-download" data-toggle="popover" data-placement="left" data-html="true" data-trigger="hover" data-content=''>
写了56812字,被9人关注,获得了8个喜欢
Scala学习笔记1——Scala入门
从使用Scala解释器开始输入任意的Scala表达式,比如输入1+2,解释器显示:res0:Int = 3
这行显示包括:
一个由Scala解释器自动生成的变量名或者由你指定的变量名用来指向计算出来的结果(比如res0代表result0变量)
一个冒号,后面紧跟个变量类型比如Int
一个等于号=
计算结果,本例为1+2的结果3
resX变量名可以用在之后的表达式中,比如:此时res0=3,如果输入res0 *3,则显示res1: Int =9。
变量定义Scala 定义了两种类型的变量val和var,val类似于Java中的final变量,一旦初始化之后,不可以重新复制(我们可以称它为常变量)。而var类似于一般的非final变量。可以任意重新赋值。
比如定义一个字符串常变量:
scala& val msg="Hello,World"
msg:String= Hello,World
这个表达式定义了一个msg变量,为字符串常量。它的类型为string(java.lang.string)。 可以看到我们在定义这个变量时并不需要像Java一样定义其类型,Scala 可以根据赋值的内容推算出变量的类型。这在Scala语言中成为“type inference”。当然如果你愿意,你也可以采用和Java一样的方法,明确指定变量的类型,如:
scala& val msg2:String="Hello again,world"
msg2:String= Hello again,world
不过这样写就显得不像Scala风格了。此外Scala语句也不需要以分号结尾。 如果在命令行中需要分多行输入,Scala解释器在新行前面显示|,表示该行接着上一行。比如:
scala& val msg3=
|"Hello world 3rd time"
msg3:String= Hello world 3rd time
函数定义Scala既是面向对象的编程语言,也是面向函数的编程语言,因此函数在Scala语言中的地位和类是同等第一位的。
下面的代码定义了一个简单的函数求两个值的最大值:
scala&def max(x:Int,y:Int):Int ={
|if(x &y) x
max: (x: Int, y: Int)Int
Scala函数以def定义,然后是函数的名称(如max),然后是以逗号分隔的参数。Scala中变量类型是放在参数和变量的后面,以“:”隔开。这种做的一个好处是便于“type inference”。刚开始有些不习惯(如果你是Pascal程序员会觉的很亲切)。同样如果函数需要返回值,它的类型也是定义在参数的后面(实际上每个Scala函数都有返回值,只是有些返回值类型为Unit,类似为void类型)。
此外每个Scala表达式都有返回结果(这一点和Java,C#等语言不同),比如Scala的if else语句也是有返回值的,因此函数返回结果无需使用return语句。实际上在Scala代码应当尽量避免使用return语句。函数的最后一个表达式的值就可以作为函数的结果作为返回值。
同样由于Scala的“type inference”特点,本例其实无需指定返回值的类型。对于大多数函数Scala都可以推测出函数返回值的类型,但目前来说回溯函数(函数调用自身)还是需要指明返回结果类型的。
下面在定义个“没有”返回结果的函数(其它语言可能称这种无返回值的函数为程式)。
scala& def greet()= println("hello,world")
greet: ()Unit
greet函数的返回值类型为Unit 表示该函数不返回任何有意义的值,Unit类似于Java中的void类型。这种类型的函数主要用来获得函数的“副作用”,比如本函数的副作用是打印招呼语。
Scala脚本Scala本身是设计用来编写大型应用的,但它也可以作为脚本语言来执行,脚本为一系列Scala表达式构成以完成某个任务,比如前面的Hello World脚本,你也可以使用脚本来实现一些比如复制文件,创建目录之类的任务。Scala中的while循环下面的代码使用while实现一个循环:
while(i & args.length) {
println (args(i))
这里要注意的是Scala不支持++i和i++运算符,因此需要使用i += 1来加一。 这段代码看起来和Java代码差不多,实际上while也是一个函数,你自动可以利用scala语言的扩展性,实现while语句,使它看起来和Scala语言自带的关键字一样调用。
Scala访问数组的语法是使用()而非[]。
这里介绍了使用while来实现循环,但这种实现循环的方法并不是最好的Scala风格,在下一步介绍使用一种更好的方法来避免通过索引来枚举数组元素。
foreach 和 for 来实现迭代第五步使用while来实现循环,和使用Java实现无太大差异,而Scala是面向函数的语言,更好的方法是采用“函数式”风格来编写代码。比如上面的循环,使用foreach方法如下:
args.foreach(arg =& println(arg))
该表达式,调用args的foreach方法,传入一个参数,这个参数类型也是一个函数(lambda表达式,和C#中概念类似)。这段代码可以再写的精简些,你可以利用Scala支持的缩写形式,如果一个函数只有一个参数并且只包含一个表达式,那么你无需明确指明参数。因此上面的代码可以写成:
args.foreach( println)
Scala中也提供了一个称为“for comprehension”,它比Java中的for功能更强大。“for comprehension”(可称之为for表达式)将在后面介绍,这里先使用for来实现前面的例子:
for(arg &-args)
println(arg)
使用类型参数化数组
在Scala中你可以使用new来实例化一个类。当你创建一个对象的实例时,你可以使用数值或类型参数。如果使用类型参数,它的作用类似Java或.Net的Generic类型。所不同的是Scala使用方括号来指明数据类型参数,而非尖括号。比如:
val greetStrings = new Array[String](3)
greetStrings(0)= "Hello"
greetStrings(1)= ","
greetStrings(2)= "world!\n"
for(i&-0to2) print(greetStrings(i))
可以看到Scala使用[]来为数组指明类型化参数,本例使用String类型,数组使用()而非[]来指明数组的索引。其中的for表达式中使用到0 to 2,这个表达式演示了Scala的一个基本规则,如果一个方法只有一个参数,你可以不用括号和.来调用这个方法。
因此这里的0 to 2, 其实为(0).to(2)调用的为整数类型的to方法,to方法使用一个参数。Scala中所有的基本数据类型也是对象(和Java不同),因此0可以有方法(实际上调用的是RichInt的方法),这种只有一个参数的方法可以使用操作符的写法(不用.和括号),实际上Scala中表达式1+2,最终解释为(1).+(2)+也是Int的一个方法,和Java不同的是,Scala对方法的名称没有太多的限制,你可以使用符合作为方法的名称。
这里也说明为什么Scala中使用()来访问数组元素,在Scala中,数组和其它普遍的类定义一样,没有什么特别之处,当你在某个值后面使用()时,Scala将其翻译成对应对象的apply方法。因此本例中greetStrings(1)其实调用greetString.apply(1)方法。这种表达方法不仅仅只限于数组,对于任何对象,如果在其后面使用(),都将调用该对象的apply方法。同样的如果对某个使用()的对象赋值,比如:
greetStrings(0)="Hello"
Scala将这种赋值转换为该对象的update方法, 也就是greetStrings.update(0,”hello”)。因此上面的例子,使用传统的方法调用可以写成:
val greetStrings =new Array[String](3)
greetStrings.update(0,"Hello")
greetStrings.update(1,",")
greetStrings.update(2,"world!\n")
for(i&-0to2) print(greetStrings.apply(i))
从这点来说,数组在Scala中并不某种特殊的数据类型,和普通的类没有什么不同。
不过Scala还是提供了初始化数组的简单的方法,比如什么的例子数组可以使用如下代码:
val greetStrings =Array("Hello",",","World\n")
这里使用()其实还是调用Array类的关联对象Array的apply方法,也就是:
val greetStrings =Array.apply("Hello",",","World\n")
ListsScala也是一个面向函数的编程语言,面向函数的编程语言的一个特点是,调用某个方法不应该有任何副作用,参数一定,调用该方法后,返回一定的结果,而不会去修改程序的其它状态(副作用)。这样做的一个好处是方法和方法之间关联性较小,从而方法变得更可靠和重用性高。使用这个原则也就意味着就变量的设成不可修改的,这也就避免了多线程访问的互锁问题。
前面介绍的数组,它的元素是可以被修改的。如果需要使用不可以修改的序列,Scala中提供了Lists类。和Java的List不同,Scala的Lists对象是不可修改的。它被设计用来满足函数编程风格的代码。它有点像Java的String,String也是不可以修改的,如果需要可以修改的String对像,可以使用StringBuilder类。
比如下面的代码:
val oneTwo =List(1,2)
val threeFour =List(3,4)
val oneTwoThreeFour=oneTwo ::: threeFour
println (oneTwo +" and "+ threeFour +" were not mutated.")
println ("Thus, "+ oneTwoThreeFour +" is a new list")
定义了两个List对象oneTwo和threeFour,然后通过:::操作符(其实为:::方法)将两个列表链接起来。实际上由于List的不可以修改特性,Scala创建了一个新的List对象oneTwoThreeFour来保存两个列表连接后的值。
List也提供了一个::方法用来向List中添加一个元素,::方法(操作符)是右操作符,也就是使用::右边的对象来调用它的::方法,Scala中规定所有以:开头的操作符都是右操作符,因此如果你自己定义以:开头的方法(操作符)也是右操作符。
如下面使用常量创建一个列表:
valoneTowThree =1::2::3:: Nil
println(oneTowThree)
调用空列表对象Nil的::方法 也就是:
valoneTowThree =
Nil.::(3).::(2).::(1)
Scala 的List类还定义其它很多很有用的方法,比如head、last、length、reverse、tail等。这里就不一一说明了,具体可以参考List的文档。
TuplesScala中另外一个很有用的容器类为Tuples,和List不同的是,Tuples可以包含不同类型的数据,而List只能包含同类型的数据。Tuples在方法需要返回多个结果时非常有用。(Tuple对应到数学的矢量的概念)。
一旦定义了一个元组,可以使用._和索引来访问员组的元素(矢量的分量,注意和数组不同的是,元组的索引从1开始)。
val pair=(99,"Luftballons")
println(pair._1)
println(pair._2)
元组的实际类型取决于它的分量的类型,比如上面pair的类型实际为Tuple2[Int,String],而(‘u’,’r’,”the”,1,4,”me”)的类型为Tuple6[Char,Char,String,Int,Int,String]。
目前Scala支持的元组的最大长度为22。如果有需要,你可以自己扩展更长的元组。
Sets和MapsScala语言的一个设计目标是让程序员可以同时利用面向对象和面向函数的方法编写代码,因此它提供的集合类分成了可以修改的集合类和不可以修改的集合类两大类型。比如Array总是可以修改内容的,而List总是不可以修改内容的。类似的情况,Scala也提供了两种Sets和Map集合类。
比如 Scala API 定义了Set的基Trait类型Set(Trait的概念类似于Java中的Interface,所不同的Scala中的Trait可以有方法的实现),分两个包定义Mutable(可变)和Immutable(不可变),使用同样名称的子Trait。下图为Trait和类的基础关系:
使用Set的基本方法如下:
varjetSet = Set ("Boeing","Airbus")jetSet +="Lear"println(jetSet.contains("Cessna"))
缺省情况Set为Immutable Set,如果你需要使用可修改的集合类(Set类型),你可以使用全路径来指明Set,比如scala.collection.mutalbe.Set。
Scala提供的另外一个类型为Map类型,Scala也提供了Mutable和Immutable两种 Map 类型,如下图所示。
Map的基本用法如下(Map类似于其它语言中的关联数组如PHP)
val romanNumeral = Map (1-&"I",2-&"II",3-&"III",4-&"IV",5-&"V")
println (romanNumeral(4))
学习识别函数编程风格
Scala语言的一个特点是支持面向函数编程,因此学习Scala的一个重要方面是改变之前的指令式编程思想(尤其是来自Java或C#背景的程序员),观念要向函数式编程转变。首先在看代码上要认识哪种是指令编程,哪种是函数式编程。实现这种思想上的转变,不仅仅会使你成为一个更好的Scala程序员,同时也会扩展你的视野,使你成为一个更好的程序员。一个简单的原则,如果代码中含有var类型的变量,这段代码就是传统的指令式编程,如果代码只有val变量,这段代码就很有可能是函数式代码,因此学会函数式编程关键是不使用vars来编写代码。
来看一个简单的例子:
def printArgs( args: Array[String]):Unit ={
while(i & args.length) { println (args(i))
来自Java背景的程序员开始写Scala代码很有可能写成上面的实现。我们试着去除vars变量,可以写成跟符合函数式编程的代码:
def printArgs( args: Array[String]):Unit ={for( arg &- args)
println(arg)}
或者更简化为:
defprintArgs( args: Array[String]):Unit ={args.foreach(println)}
这个例子也说明了尽量少用vars的好处,代码更简洁和明了,从而也可以减少错误的发生。因此Scala编程的一个基本原则上,能不用vars,尽量不用vars,能不用mutable变量,尽量不用mutable变量,能避免函数的副作用,尽量不产生副作用。
使用脚本实现某个任务,通常需要读取文件,本节介绍Scala读写文件的基本方法。比如下面的例子读取文件的每行,把该行字符长度添加到行首:
import scala.io.Source
if(args.length&0){
for( line &- Source.fromFile(args(0)).getLines())
println(line.length+" "+ line)
else Console.err.println("Please enter filename")
可以看到Scala引入包的方式和Java类似,也是通过import语句。文件相关的类定义在scala.io包中。 如果需要引入多个类,Scala使用 “_” 而非 “*”.
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:

我要回帖

更多关于 scala 函数返回值 的文章

 

随机推荐