[Scala基础系列 02]Scala函数

本文主要内容如下:

  • 变量和不变量
  • 函数和过程
  • 函数的参数
  • 分号

1.变量和不变量

1.1.变量

Scala的变量分两种,var和val。var,即variable,类似于我们在Java等其他语言中接触到的变量,而val,是value,类似于我们在其他语言中用到的不可重新赋值的常量,或者final变量。
为什么会有这种区别,这是由于很多情况下,其实你不需要一个可变的var,尤其在函数式编程中,更为明显。不变性能给程序带来很多便利,因此Scala非常强调不可变(immutable)的概念。关于不可变的探讨,后续文章将会进行讨论。

定义变量(var)和值(val)

定义常量或变量,如下:

val name = "Chunni"
var number = 5

以上,我们并没有指定变量的类型,但是Scala编译器通过类型推断(Type Inference)可推断出数据类型。当然,也可以显示指定变量类型,不过,格式与Java不同,类型是在变量名称后,用冒号(:)分隔,比如:

val age: Int = 30

一般来说,当类型不容易判断(对读者来说,不是对机器,编译器总是可以推断类型的),或可能引起误解时,最好显示指定,以增加程序可读性。通常,在类型显而易见时,省略类型反而使程序更简洁易理解。
变量,即使是不可变的值,也可以是某表达式的结果:

val msg = "Hello " + name

Scala允许一次定义多个变量。

var i, j = 5
val anonymous, unknown = "Anonym"

2.函数和过程

2.1.函数(function)

现在我们可看一下怎么定义函数。

def add(x: Int, y: Int) : Int = {
  x + y
}
println("2 + 3 = " + add(2,3))

由上面代码可以看到,函数定义以def开始,然后是函数名称,接下来,小括号内是函数的参数列表,参数之间逗号分隔。与Java或C不同的是,参数的类型出现在参数名之后,与参数名称冒号分隔。 函数的类型(也就是返回值的类型)在参数列表之后,也用冒号分隔。在函数类型之后,是等号“=”,然后才是大括号包围起来的函数体。
函数返回类型可以省略,因为编译器可以推断出来。不过,为了代码的可读性,应该尽量注明返回类型,只有在代码非常简短,能一眼看出返回类型的情况下,可省略它。

需要说明的是:


参数类型是不可以省略的,因为编译器没可能推断参数的类型

 函数签名与函数体之间的“=”,在函数有返回值(也就是说是函数而不是过程)时不能省略

2.1.过程(procedure)

过程的目的是为了某种“副作用”,而不是为了得到计算结果。如上所述,过程只是一种特殊的函数,具体来说,是没有返回值,或者说返回类型为Unit的函数。

def sayHiTo(name: String) {
  println("Hi, " + name)
}
sayHiTo("Nini")

由上可知,过程不需要标明返回类型,也不需要"="。有的程序员为了代码风格与函数保持一致,而加上"=",编译器也可以接受。

3.函数的参数

Scala支持命名参数和可选参数,另外,也支持重复参数。

3.1.命名参数

命名参数可让你在传参时指定参数名,这样,参数的位置将不再重要。

def addUser(name: String, age: Int, phone: String) = {
  println("User added, name: %s, age: %d, phone number: %s".format(name, age, phone))
}

addUser("Tony", 35, "702-201-1234")
addUser(name = "Tim", phone = "702-201-2345", age = 33)
addUser("Abby", phone = "702-201-3456", age = 28)
addUser("Abby",  age = 28, "702-201-3456")
//addUser("Abby", "702-201-3456", age = 28)
// above line wouldn‘t compile
// Error: parameter ‘age‘ is already specified at parameter position 2

上述代码中,addUser(name = "Tim", phone = "702-201-2345", age = 33)使用了命名参数,这样,参数顺序可以跟函数定义的不一样。此外,命名参数跟普通的按位置的参数可以混合使用,比如addUser("Abby", phone = "702-201-3456", age = 28)

需要说明的是:


混合使用时,不过,普通参数的位置,必须跟函数定义相吻合,因此addUser("Abby", "702-201-3456", age = 28)会编译出错,因为‘phone‘应该出现在第三项。

3.2.默认参数

与C++类似,Scala支持默认参数,在函数定义时,可以指定某些参数的默认值,这样,在调用时可以省略一些参数。

def log(msg: String, severity: String = "Info", time: Long = System.currentTimeMillis()) {
  println("[%d] <%s> %s".format(time,severity, msg))
}

val t = System.currentTimeMillis() + 200
log("use default parameters")
log("specify severity", "Warn")
log("specify time", time = t)
log("specify both severity and time", "Warn", t)

在有默认参数的情况下,假如默认值能符合需要,则调用时可以不用传递进去,比如 log("use default parameters"),这样函数就会直接使用默认值。当然你可以可以显示传入参数。

当只有部分参数需要传入时,它们的位置显然完全跟定义的吻合,比如log("specify time", time = t)。这时,命名参数了就起了大作用了。这也是为什么命名参数和默认参数经常一起出现的原因。

3.3.重复参数

下面的‘log‘函数有一个参数,其类型后面有一个‘*‘,这表示这个参数可以重复不定次数,包括0次。

def log(msgs: String*) = {
  println(msgs.getClass.getName)
  println(msgs.mkString(","))
}

log()
log("one","two","three")
val array = Array("one","two","three")
//log(array)
//above line wouldn‘t compile, type mismatch, expected String
log(array: _*)

如果查看过结果,你可能已经注意到,当参数个数不是0时,msgs在内部其实是一个Array。使用时跟Array差不多,只是,调用时不能传递直接Array进来。这时因为调用时重复参数是被当做个体,而不是将全部参数当做整体看待。

如果需要传递整个Array(或者别的类型的序列)的话,有一个变通方法,那就是,加一个‘_*‘符号,该符号与参数之间用逗号分隔,比如log(array: _*)

4.分号

4.1.行内语句

大部分情况下,我们的编程习惯是一个语句占用一行,而多数语言要求在语句结束有一个分号,这在Scala设计者看来是个浪费,Scala希望尽可能节省程序员的键盘敲击次数,因此,Scala被设计为行结束默认为语句结束。 但是,如果你想要在一行内输入多个语句,则分号无法避免。

val hi = "Hi, Nini"; println(msg)

4.2.语句跨行

如果你需要输入跨行的语句,这在初始化字符串或书写复杂的数学表达式时经常发生。比如:

val msg = "Hello everybody, "
          + "my name is Nini"  //Error: value unary_+ is not a member of String
val ret = 3 + 4
          + 5

上述代码不会按你预想的,将语句视为跨行,相反,会被当作四行独立的语句,"Hello everybody, "被赋值给msg,第二行出错,ret的值是7,第四行是一个独立的值+5。 如果你需要他们被视为跨行的语句,你得使用括号,或者将操作符放在未结束的行尾,它将被当作语句位结束的标志。如:

val hi = "Hi, Nini"; println(hi)
val msg = ("Hello everybody,"
         + "my name is Nini")    //A statement is not over if the parentheses don‘t match
println(msg)
val ret = 3 + 4 +                //This is a sign that the statement is not over
          5
println(ret)

这一次,msg被正确的赋值,ret也被正确的计算为12。

分号推断规则

分号推断的规则很简单。

  1. 默认情况下,行结束被视为一个分号,也就是语句结束
  2. 下列情况语句将被视为未结束 &nbsp;&nbsp;行结束位于括号中(小括号()或者中括号[]均可) &nbsp;&nbsp;行结束于不能作为语句结束的字符,比如中缀操作符(+,-,*,/ 等)
时间: 2024-10-02 04:03:33

[Scala基础系列 02]Scala函数的相关文章

[Scala基础系列 04]Scala基本类型

1.Scala的数值类型 Scala的数值类型与Java类似,他们的范围与Java也是一致的.与Java不同的是,他们都是对象,是相应的数值类的实例.Scala通过富包装(Rich Wrapper)类给这些数值类型提供了强大的支持. 1.1.数值类型 Scala的数值类型和取值范围,见下表. Boolean: true 或者 false Byte: 8位, 有符号(2-7 ~ 27 - 1) Short: 16位, 有符号 (2-15 ~ 215 - 1) Int: 32位, 有符号 (2-31

[Scala基础系列 03]Scala操作符

1.Scala操作符简介 首先,请记住,Scala没有操作符!也没有通常意义上的表达式.你所见到的类似操作符和表达式的语句,其实是方法(函数),它们只是方法的一种比较直观的写法,可以叫做操作符记法. 1.1.二元操作符(中缀表达式) 二元操作符是最常见的操作符,比如,一个简单的表达式1 + 2.其实,“+”是定义在Int类的一个方法,你完全可以用普通方法调用的写法1.+(2).相应的,其他的方法,比如"Hello".drop(2),也可以用操作符记法,"Hello"

[Scala基础系列 05]Scala控制结构

1.If语句 Scala的If语句可以完成其他语言中If语句,于此同时,if/else通常还有值,可以用来赋值,或者代替三元条件运算符(?:).不过它可以比条件运算符更强大,因为你可以在if-else里面写很复杂的程序块. 1.1.普通的If语句 package com.tv189.foundation /** * Created by molyeo on 2015/7/30. */ object IfCondition { def main(args: Array[String]) { val

[Scala基础系列 06]Scala类和对象

1.类和构造函数 Scala中的类,基本概念与其他面向对象语言是一致的,不过在语法上有些不一样的地方.与Java等语言相比,Scala的类语法更简洁,使用起来也更方便. 1.1.类的基本语法 我们先来看一个简单的类定义和使用的代码. class ScoreCalculator { private var total, count = 0 def report(score: Int) { total += score count += 1 } def score = if (count == 0)

[Scala基础系列 08]Scala继承、抽象类、接口trait以及AOP实现

1.继承 和java一样,scala采用extends关键字继承基类.代码实例如下: /** * Created by molyeo on 2015/8/11. */ class Person(val name: String, var age: Int) { println("The primary constructor of Person") val school = "BJU" def sleep = "8 hours" override

[Scala基础系列 10]Scala泛型、类型边界

1.泛型和类型边界 1.1.上限(upper bounds) 我们先看一个简单的实例,用于判断两个变量中较大的值,其中两个变量的类型均为Int型 package com.tv189.advanced /** * Created by molyeo on 2015/8/12. */ class PairInt(val first: Int, val second: Int) { def bigger = { if (first.compareTo(second) > 0) first else s

[Scala基础系列 07]Scala集合

Scala有一个非常通用,丰富,强大,可组合的集合库:集合是高阶的(high level)并暴露了一大套操作方法.很多集合的处理和转换可以被表达的简洁又可读,但不审慎地用它们的功能也会导致相反的结果.每个Scala程序员应该阅读 集合设计文档:通过它可以很好地洞察集合库,并了解设计动机. 1.数组(Array&ArrayBuffer) 1.1.Array 数组(Array)其实并不在scala.collection包里面,它属于scala包,直接对应于Java的数组,比如,Scala中的Arra

Scala基础篇-02函数与代码块

1.block 代码块也是表达式,其最终求得的值是最后一个表达式的值. {exp1;exp2} { exp1 exp2 } 2.function def funtionName(param:ParamType):ReturnType{ //function body: expressions } 3.例子 利用字符串插值特性:s"...${...}..." 省略花括号: 原文地址:https://www.cnblogs.com/moonlightml/p/9864560.html

Scala基础篇-控制结构和函数

1. 条件表达式 scala> if(x>1)"positive" else -1 2. 循环 while(n>0){ } for(i <- 0 to 10){ println(i) } for(i <- 表达式)语法结构表示让变量遍历右边表达式的所有值.