关系表达式

关系表达式是包含关系操作符的表达式。关系操作符包括 6 种:相等(==)、不等(!=)、小于(<)、小于等于(<=)、大于(>)、大于等于(>=)。关系操作符都是二元操作符,并且要求两个操作数的类型是一样的。关系表达式的类型是 Bool 类型,即值只可能是 true 或 false。关系操作符的优先级和结合性见下文。

关系表达式的语法定义为:

equalityComparisonExpression
: comparisonOrTypeExpression (equalityOperator comparisonOrTypeExpression)?;
comparisonOrTypeExpression
: shiftingExpression (comparisonOperator shiftingExpression)?
| ...
;
equalityOperator
: '!=' | '=='
;
comparisonOperator
: '<' | '>' | '<=' | '>=';

关系表达式举例:

main(): Int64 {
3 < 4 // return true
3 <= 3 // return true
3 > 4 // return false3 >= 3 // return true
3.14 == 3.15 // return false3.14 != 3.15 // return true
return 0
}

需要注意的是,关系运算符是非结合(non-associative)运算符,即无法写出类似于 a < b < c 这样的表达式。

main(): Int64 {
3 < 4 < 5 // error: `<` is non-associative
3 == 3 != 4 // error: `==` and `!=` are non-associativereturn 0
}

type test 和 type cast 表达式

type test 表达式是包含操作符 is 的表达式,type cast 表达式是包含操作符 as 的表达式。is 和 as 的优先级和结合性参见下文。

type test 和 type cast 表达式的语法定义为:

comparisonOrTypeExpression
: ...
| shiftingExpression ('is' type)?
| shiftingExpression ('as' userType)?;

is 操作符

e is T 是一个用于类型检查的表达式,e is T 的类型是 Bool。其中 e 可以是任何类型的表达式,T 可以是任何类型。

当 e 的运行时类型 R 是 T 的子类型时,e is T 的值为 true,否则值为 false。

is 操作符举例:

open class Base {
var name: String = "Alice"
}
class Derived1 <: Base {
var age: UInt8 = 18
}
class Derived2 <: Base {
var gender: String = "female"
}
main(): Int64 {
var testVT = 1 is Int64 // testVT = truetestVT = 1 is String // testVT = falsetestVT = true is Int64 // testVT = false
testVT = [1, 2, 3] is Array<Int64> // testVT = truelet base1: Base = Base()
let base2: Base = Derived1()
let base3: Base = Derived2()
let derived1: Derived1 = Derived1()
let derived2: Derived2 = Derived2()
var test = base1 is Base // test = truetest = base1 is Derived1 // test = falsetest = base1 is Derived2 // test = falsetest = base2 is Base // test = truetest = base2 is Derived1 // test = truetest = base2 is Derived2 // test = falsetest = base3 is Base // test = truetest = base3 is Derived1 // test = falsetest = base3 is Derived2 // test = truetest = derived1 is Base // test = truetest = derived1 is Derived1 // test = truetest = derived1 is Derived2 // test = falsetest = derived2 is Base // test = truetest = derived2 is Derived1 // test = falsetest = derived2 is Derived2 // test = truereturn 0
}

as 操作符

e as T 是一个用于类型转换的表达式,e as T 的类型是 Option。其中 e 可以是任何类型的表达式,T 可以是任何具体类型。

当 e 的运行时类型 R 是 T 的子类型时,e as T 的值为 Some(e),否则值为 None。

as 操作符举例:

open class Base {
var name: String = "Alice"}
class Derived1 <: Base {
var age: UInt8 = 18}
class Derived2 <: Base {
var gender: String = "female"
}
main(): Int64 {
let base1: Base = Base()
let base2: Base = Derived1()
let base3: Base = Derived2()
let derived1: Derived1 = Derived1()let derived2: Derived2 = Derived2()
let castOP1 = base1 as Base // castOP = Option<Base>.Some(base1)
let castOP2 = base1 as Derived1 // castOP = Option<Derived1>.None
let castOP3 = base1 as Derived2 // castOP = Option<Derived2>.None
let castOP4 = base2 as Base // castOP = Option<Base>.Some(base2)
let castOP5 = base2 as Derived1 // castOP = Option<Derived1>.Some(base2)
let castOP6 = base2 as Derived2 // castOP = Option<Derived2>.None
let castOP7 = base3 as Base // castOP = Option<Base>.Some(base3)
let castOP8 = base3 as Derived1 // castOP = Option<Derived1>.None
let castOP9 = base3 as Derived2 // castOP = Option<Derived2>.Some(base3)
let castOP10 = derived1 as Base // castOP = Option<Base>.Some(derived1)
let castOP11 = derived1 as Derived1 // castOP = Option<Derived1>.Some(derived1)let castOP12 = derived1 as Derived2 // castOP = Option<Derived2>.None
let castOP13 = derived2 as Base // castOP = Option<Base>.Some(derived2)
let castOP14 = derived2 as Derived1 // castOP = Option<Derived1>.None
let castOP15 = derived2 as Derived2 // castOP = Option<Derived2>.Some(derived2)return 0
}

位运算表达式

位运算表达式是包含位运算操作符的表达式。仓颉编程语言支持 1 种一元前缀位运算操作符:按位求反(!),以及 5 种二元中缀位运算操作符:左移(<<)、右移(>>)、按位与(&)、按位异或(^)和按位或(|)。位运算操作符的操作数只能为整数类型,通过将操作数视为二进制序列,然后在每一位上进行逻辑运算(0视为 false,1 视为 true )或移位操作来实现位运算。&、^ 和 | 的操作中,位与位之间执行的是逻辑操作(参见逻辑表达式)。位运算操作符的优先级和结合性参见下文。

位运算表达式的语法定义为:

prefixUnaryExpression
: prefixUnaryOperator* incAndDecExpression
;
prefixUnaryOperator
: '!'
| ...
;
bitwiseDisjunctionExpression
: bitwiseXorExpression ( '|' bitwiseXorExpression)*
;
bitwiseXorExpression
: bitwiseConjunctionExpression ( '^' bitwiseConjunctionExpression)*;
bitwiseConjunctionExpression
: equalityComparisonExpression ( '&' equalityComparisonExpression)*;
shiftingExpression
: additiveExpression (shiftingOperator additiveExpression)*
;
shiftingOperator
: '<<' | '>>'
;

位运算表达式举例:

func foo(): Unit {
!10 // The result is -11!20 // The result is -2110 << 1 // The result is 2010 << 1 << 1 // The result is 4010 >> 1 // The result is 5
10 & 15 // The result is 1010 ^ 15 // The result is 5
10 | 15 // The result is 151 ^ 8 & 15 | 24 // The result is 25}

对于移位操作符,要求其操作数必须是整数类型(但两个操作数的类型可以不一样),并且无论左移还是右移,右操作数都不允许为负数(对于编译时可检查出的此类错误,编译报错,如果运行时发生此错误,则抛出异常)。

对于无符号数的移位操作,移位和补齐规则是:左移低位补 0 高位丢弃,右移高位补 0 低位丢弃。对于有符号数的移位操作,移位和补齐规则是:

正数和无符号数的移位补齐规则一致;2. 负数左移低位补 0 高位丢弃;
3. 负数右移高位补 1 低位丢弃。

let p: Int8 = -30
let q = p << 2 // q = -120let r = p >> 2 // r = -8
let r = p >> -2 // error
let x: UInt8 = 30
let b = x << 3 // b = 240
let b = x >> 1 // b = 15

另外,如果右移或左移的位数(右操作数)等于或者大于操作数的宽度,则为 overshift,如果编译时可以检测到则报错,否则运行时抛出异常。

let x1 : UInt8 = 30 // 0b00011110
let y1 = x1 >> 11 // compilation error

区间表达式

区间表达式是包含区间操作符的表达式。区间表达式用于创建 Range 实例。区间表达式的语法定义为:

: bitwiseDisjunctionExpression ('..=' | '..') bitwiseDisjunctionExpression
↪ (':' bitwiseDisjunctionExpression)?
| bitwiseDisjunctionExpression
;

区间操作符有两种:… 和…=,分别用于创建 “左闭右开” 和 “左闭右闭” 的 Range 实例。关于它们的介绍,请参见Range 类型。

逻辑表达式

逻辑表达式是包含逻辑操作符的表达式。逻辑操作符的操作数只能为 Bool 类型的表达式。仓颉编程语言支持 4 种逻辑操作符:逻辑非(!)、逻辑与(&&)、逻辑或(||)。它们的优先级和结合性参见下文。

逻辑表达式的语法定义为:

prefixUnaryExpression
: prefixUnaryOperator* incAndDecExpression
;
prefixUnaryOperator
: '!'
| ...
;
logicDisjunctionExpression
: logicConjunctionExpression ( '||' logicConjunctionExpression)*;
logicConjunctionExpression
: rangeExpression ( '&&' rangeExpression)*
;

逻辑非(!)是一元操作符,它的作用是对其操作数的布尔值取反:!false 的值等于 true,!true 的值等于false。

逻辑与(&&)和逻辑或(||)均是二元操作符。对于表达式 expr1 && expr2,只有当 expr1 和 expr2的值均等于 true 时,它的值才等于 true;对于表达式 expr1 || expr2,只有当 expr1 和 expr2 的值均等于 false 时,它的值才等于 false。

&& 和 || 采用短路求值策略:计算 expr1 && expr2 时,当 expr1=false 则无需对 expr2 求值,整个表达式的值为 false;计算 expr1 || expr2 时,当 expr1=true 则无需对 expr2 求值,整个表达式的值为true。

main(): Int64 {
let expr1 = false
let expr2 = true
!true // Logical NOT, return false.
1 > 2 && expr1 // Logical AND, return false without computing↪ the value of expr1.
1 < 2 || expr2 // Logical OR, return true without computing
↪ the value of expr2.
return 0
}

coalescing 表达式

coalescing 表达式是包含 coalescing 操作符的表达式。coalescing 操作符使用 ?? 表示,?? 是二元中缀操作符,其优先级和结合性参见下文。

coalescing 表达式的语法定义为:

coalescingExpression
: logicDisjunctionExpression ('??' logicDisjunctionExpression)*
;

coalescing 操作符用于 Option 类型的解构。假设表达式 e1 的类型是 Option,对于表达式 e1 ??e2,规定:

表达式 e2 具有类型 T。

  1. 表达式 e1 ?? e2 具有类型 T。
  2. 当 e1 的值等于 Option.Some(v) 时,e1 ?? e2 的值等于 v 的值(此时,不会再去对 e2 求值,即满足 “短路求值”);当 e1 的值等于 Option.None 时,e1 ?? e2 的值等于 e2 的值。

表达式 e1 ?? e2 是如下 match 表达式的语法糖:

// when e1 is Option<T>
match (e1) {
case Some(v) => v
case None => e2
}
coalescing 表达式使用举例:
main(): Int64 {
let v1 = Option<Int64>.Some(100)let v2 = Option<Int64>.None
let r1 = v1 ?? 0
let r2 = v2 ?? 0
print("${r1}") // output: 100
print("${r2}") // output: 0
return 0}

流表达式

流表达式是包含流操作符的表达式。流操作符包括两种:表示数据流向的中缀操作符 |>(称为 pipeline)和表示函数组合的中缀操作符 ~>(称为 composition)。|> 和 ~> 的优先级相同,并介于 || 和赋值操作符 = 之间。|> 和 ~> 的结合性均为左结合,详情参考下文。流表达式的语法定义为:

flowExpression
: logicDisjunctionExpression (flowOperator logicDisjunctionExpression)*;
flowOperator
: '|>' | '~>'
;

pipeline 操作符

pipeline 表达式是单个参数函数调用的语法糖,即 e1 |> e2 是 let v = e1; e2(v) 的语法糖(即先对 |> 操作符左边的 e1 求值)。这里 e2 是函数类型的表达式,e1 的类型是 e2 的参数类型的子类型;或者e2 的类型重载了函数调用操作符 ()(参见可以被重载的操作符)。

注意:这里的 f 不能是 init 和 super 构造函数。

func f(x: Int32): Int32 { x + 1 }
let a: Int32 = 1
var res = a |> f // ok
var res1 = a |> {x: Int32 => x + 1} // ok
func h(b: Bool) { b }
let res3 = a < 0 || a > 10 |> h // Equivalence:(a < 0 || a > 10) |> hfunc g<T>(x: T): T { x }
var res4 = a |> g<Int32> // ok
class A {
let a: Int32
let b: Int32
init(x: Int32) {
a = x
b = 0
}
init(x: Int32, y: Int32) {
x |> init // error: `init` is not a valid expressionb = y
}
}
// PIPELINE with operator `()` overloading
class A {
operator func ()(x: Int32) {
x
}
}
let obj = A()
let a: Int32 = 1
let res = a |> obj // Equivalence:obj(a)
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐