链式比较

一起使用的多个比较运算符被链接,就像通过 && 运算符连接一样 。这对于可读和数学上简洁的比较链非常有用,例如

# same as 0 < i && i <= length(A)
isinbounds(A, i)       = 0 < i ≤ length(A)

# same as Set() != x && issubset(x, y)
isnonemptysubset(x, y) = Set() ≠ x ⊆ y

然而,a > b > ca > b && b > c 之间有一个重要的区别; 在后者中,术语 b 被评估两次。这对于普通的旧符号来说并不重要,但如果术语本身具有副作用则可能很重要。例如,

julia> f(x) = (println(x); 2)
f (generic function with 1 method)

julia> 3 > f("test") > 1
test
true

julia> 3 > f("test") && f("test") > 1
test
test
true

让我们通过查看它们如何被解析并降低到表达式中来深入研究链式比较及其工作原理。首先,考虑简单的比较,我们可以看到它只是一个普通的旧函数调用:

julia> dump(:(a > b))
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol >
    2: Symbol a
    3: Symbol b
  typ: Any

现在,如果我们链接比较,我们注意到解析已经改变:

julia> dump(:(a > b >= c))
Expr
  head: Symbol comparison
  args: Array{Any}((5,))
    1: Symbol a
    2: Symbol >
    3: Symbol b
    4: Symbol >=
    5: Symbol c
  typ: Any

解析后,表达式然后降低到最终形式:

julia> expand(:(a > b >= c))
:(begin 
        unless a > b goto 3
        return b >= c
        3: 
        return false
    end)

我们确实注意到这与 a > b && b >= c 相同:

julia> expand(:(a > b && b >= c))
:(begin 
        unless a > b goto 3
        return b >= c
        3: 
        return false
    end)