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

1.Scala操作符简介

首先,请记住,Scala没有操作符!也没有通常意义上的表达式。你所见到的类似操作符和表达式的语句,其实是方法(函数),它们只是方法的一种比较直观的写法,可以叫做操作符记法。

1.1.二元操作符(中缀表达式)

二元操作符是最常见的操作符,比如,一个简单的表达式1 + 2。其实,“+”是定义在Int类的一个方法,你完全可以用普通方法调用的写法1.+(2)。相应的,其他的方法,比如"Hello".drop(2),也可以用操作符记法,"Hello" drop 2。选择哪种书写方式,只需要考虑代码可读性,对编译器而言没有差别。

val sum1 = 1 + 2                                //3
println("1 + 2 = " + sum1)

val sum2 = (1).+(2)                             //3
println("(1).+(2) = " + sum2)

val str1 = "Hello".drop(2)                      //"llo"
println("\"Hello\".drop(2) = " + str1)

val str2 = "Hello" drop 2                       //"llo"
println("\"Hello\" drop 2 = " + str2)

由上面代码可以看到,操作符跟方法没有区别。操作符与方法的统一,是Scala的一大特点。

1.2.一元操作符(前缀/后缀表达式)

能做前缀的操作符很少,只有四个:+,-,!,~。另外,前缀表达式有一些特别,它们的方法需要把对应的操作符前加上unary_,比如unary_!,或者unary_-

println(-2.0)
println((2.0).unary_-)

println(true)
println(false.unary_!)

请注意

除了上述四个前缀操作符外,即使定义其他的unary_method,这个方法也不会成为前缀操作符,比如你可以定义unary_*方法,你可以可以正常调用i.unary_*,但是不能用在前缀表达式里*i

后缀表达式则没有上述限制。所有无参数的方法,都可以写作后缀表达式,比如i toString 相当于 i.toString()

1.3.操作符重载

由于操作符本质上就是方法,你可以跟方法重载一样重载操作符。C++与C#支持操作符重载,只是不像方法重载这样自然,而Java不允许操作符重载,因此,Scala的这种机制无疑有巨大优势。 比如,由于Java不支持操作符重载,对于表达式x * x * x,当x是原生类型int时,可以这样写,但是如果x是BigInteger时,你只能写成x.multiply(x).multiply(x), 这就不怎么漂亮了。 在Scala中就没有这种问题,BigInt中定义的*方法,可以直接这样写x * x * x,或者,任意你自己定义的类,也可以定义类似的操作符。

另外,也是由于操作符就是方法,你可以定义任意你想要的操作符,比如BigInt类就有一个方法/%,这个方法会返回一对数值,商和余数,与Java的BigInteger中的divideAndRemainder方法类似。

val x: BigInt = 1003
println(x * x * x)      //1009027027
println(x /% 5)         //(200,3)

2.操作符的类型

操作符,大体上分为算术操作符,关系逻辑操作符和位操作符。

2.1.算术操作符

在Scala中,以中缀运算符的写法书写数学表达式,使用上与其他语言没有差别。 比如,1 + 2, 2.5 - 5, 3 * 4, 6 / 4, 10 % 3, ‘A‘ - ‘a‘
区别在于,算术操作符也可以用于其他非简单类型的类中。

2.2.关系逻辑操作符

2.2.1.关系操作符

关系操作符,与其他大部分语言类似,比较两个对象,产生一个布尔型的结果。比如,1 > 2, 3 < 4, ‘a‘ <= ‘b‘, 2.3 >= 2.3, obj1 == obj2

请注意
==!=永远是比较两个对象的值,而不是像Java那样会比较对象的引用,这更符合人们的习惯。如果要比较对象引用,请使用对象的eq方法

val str1 = "abcd"
val str2 = "abcd"
println(str1 == str2)  //true

2.2.2.逻辑操作符

逻辑操作符,逻辑与(&&),逻辑或(||),类似于Java等其他语言,由两个布尔操作数,产生一个布尔型的结果,比如true && false, (1 < 2) || (2 > 3)
需要注意的是,与Java类似,逻辑操作符有短路(short-circuited)计算:只计算最少能决定结果的部分,也就是说,如果左侧的表达式已经能决定整个表达式的结果,右侧的表达式就不会计算。
我们都知道,true || (any statement) 的结果都是true,所以右侧表达式不会被计算。同样的,fasle && (any statement) 的结果都是false,右侧的表达式也不会被计算。

def trueSta = {println("evaluate 1 < 2 = true");1 < 2}
def falseSta = {println("evaluate 2 > 3 = false"); 2 > 3}
println(trueSta)
println(falseSta)

println("------------------------------")
println("Short-circuit (true || anything ):")
val ret = trueSta || falseSta

println("------------------------------")
println("Short-circuit (false && anything ):")
val ret1 = falseSta && trueSta

2.3.位操作符

Scala给整数类型提供的位操作符有:按位与(&),按位或(|),按位异或(^),和按位取补操作。另外,还有三个位移操作:左移,右移和无符号右移。这些操作与其他语言相比没有特别之处,不过,由于很多程序员不习惯位操作,所以,我们来做几个练习。

println("1 & 2 = " + (1 & 2))     //1 & 2 = 0
println("1 | 2 = " + (1 | 2))     //1 | 2 = 3
println("2 ^ 3 = " + (2 ^ 3))     //2 ^ 3 = 1
println("~4 = " + (~4))           //~4 = -5

println("4 >> 1 = " + (4 >> 1))   //4 >> 1 = 2
println("4 << 2 = " + (4 << 2))   //4 << 2 = 16

println("-1 >> 31 = " + (-1 >> 31)) //-1 >> 31 = -1
println("-1 >>> 31 = " + (-1 >>> 31)) //-1 >>> 31 = -1

前面的四个表达式比较简单,1 & 2也就是00001 & 0010,产生的结果是0000,也就是0,1 | 2,就是0001 | 0010,结果是0011也就是3,0010 ^ 0011,结果为0001也就是1。 第四个需注意,取反是符号位也会取反的,因此,0000 0000 0000 0000 0000 0000 0000 0100,取反的结果是1111 1111 1111 1111 1111 1111 1111 1011,因此变成了一个负数,-5。

移位操作,尤其是左移或右移一位的操作,在实际编程中很实用,将一个整数右移(准确的说,无符号右移)一位,相当于将它除以2,而左移一位,则相当于乘以2。最后的两个表达式,帮助比较右移和无符号右移。

参考文献:

http://meetfp.com/zh/scala-basic/operators-ex

时间: 2024-11-06 17:42:59

[Scala基础系列 03]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基础系列 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基础系列 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基础系列 02]Scala函数

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

[Scala基础系列 07]Scala集合

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

[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基础系列 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)

第1节 Scala基础语法:scala中的方法源码分析

val list=List(1,2,3,4) list.reduce((x:Int,y:Int)=>x+y)--->list.reduceLeft((x:Int,y:Int)=>x+y) var first = true var acc:Int = 0 op=(x:Int,y:Int)=>x+y for循环第一次循环:acc=1 first = false第二次循环:acc=op(1,2)=1+2=3第三次循环:acc=op(3,3)=3+3=6第四次循环:acc=op(6,4)=

scala 基础十二 scala apply的使用,工厂方法和单例模式的实现

1. apply 可以用来实现类似于静态的初始化类的实例,请看下面实例 package smart.iot class applyclass { } class A { def apply()=println("hello class A"); } object B { def apply()=println("hello object B"); } object applyRun { def main(args: Array[String]): Unit = {