MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Go操作符的优先级

2022-08-104.0k 阅读

Go 操作符优先级概述

在 Go 语言中,操作符的优先级决定了表达式中操作符的执行顺序。这与数学中的运算优先级类似,比如先乘除后加减。合理理解和运用操作符优先级对于编写正确、高效且易于理解的代码至关重要。如果不遵循正确的优先级,可能会导致代码逻辑错误,难以调试。

操作符优先级列表

Go 语言的操作符优先级从高到低大致如下:

  1. 括号 ():括号内的表达式优先计算。这是一种显式改变优先级的方式,通过将特定部分括起来,确保这部分表达式在其他操作之前执行。例如:
package main

import "fmt"

func main() {
    result := (2 + 3) * 4
    fmt.Println(result)
}

在这个例子中,(2 + 3) 先被计算,得到 5,然后再乘以 4,最终结果为 20。

  1. 一元操作符:包括 +(正号)、-(负号)、!(逻辑非)、^(按位取反)、*(指针取值)、&(取地址)等。这些操作符只作用于一个操作数,并且优先级较高。例如:
package main

import "fmt"

func main() {
    num := 5
    negNum := -num
    fmt.Println(negNum)

    boolVal := true
    negBool :=!boolVal
    fmt.Println(negBool)
}

这里 -numnum 取负,!boolValboolVal 取逻辑反。

  1. 乘除模操作符*(乘法)、/(除法)、%(取模)。它们的优先级相同,从左到右依次计算。例如:
package main

import "fmt"

func main() {
    result := 10 * 3 / 2 % 3
    fmt.Println(result)
}

先计算 10 * 3 得 30,再 30 / 2 得 15,最后 15 % 3 得 0。

  1. 加减操作符+(加法)、-(减法)。优先级相同,从左到右计算。例如:
package main

import "fmt"

func main() {
    result := 5 + 3 - 2
    fmt.Println(result)
}

5 + 3 得 8,再 8 - 2 得 6。

  1. 移位操作符<<(左移)、>>(右移)。例如:
package main

import "fmt"

func main() {
    num := 2
    shiftedLeft := num << 2
    shiftedRight := num >> 1
    fmt.Println(shiftedLeft)
    fmt.Println(shiftedRight)
}

num << 2 相当于 2 * 2 * 2,结果为 8;num >> 1 相当于 2 / 2,结果为 1。

  1. 按位逻辑操作符&(按位与)、^(按位异或)、|(按位或)。例如:
package main

import "fmt"

func main() {
    a := 5 // 二进制 0101
    b := 3 // 二进制 0011
    bitAnd := a & b
    bitXor := a ^ b
    bitOr := a | b
    fmt.Printf("按位与: %d (二进制: %b)\n", bitAnd, bitAnd)
    fmt.Printf("按位异或: %d (二进制: %b)\n", bitXor, bitXor)
    fmt.Printf("按位或: %d (二进制: %b)\n", bitOr, bitOr)
}

a & b 按位与操作,结果为 1(二进制 0001);a ^ b 按位异或操作,结果为 6(二进制 0110);a | b 按位或操作,结果为 7(二进制 0111)。

  1. 关系操作符<(小于)、<=(小于等于)、>(大于)、>=(大于等于)、==(等于)、!=(不等于)。例如:
package main

import "fmt"

func main() {
    a := 5
    b := 3
    less := a < b
    greaterEqual := a >= b
    equal := a == b
    notEqual := a != b
    fmt.Println(less)
    fmt.Println(greaterEqual)
    fmt.Println(equal)
    fmt.Println(notEqual)
}

这些操作符用于比较两个值的大小或是否相等,返回布尔值。

  1. 逻辑操作符&&(逻辑与)、||(逻辑或)。逻辑与和逻辑或操作符具有短路特性。例如:
package main

import "fmt"

func main() {
    a := true
    b := false
    andResult := a && b
    orResult := a || b
    fmt.Println(andResult)
    fmt.Println(orResult)
}

对于 &&,只有当左边操作数为 true 时才会计算右边操作数;对于 ||,只有当左边操作数为 false 时才会计算右边操作数。

  1. 赋值操作符=+=-=*=/=%=<<=>>=&=^=|= 等。例如:
package main

import "fmt"

func main() {
    num := 5
    num += 3
    fmt.Println(num)

    num <<= 2
    fmt.Println(num)
}

num += 3 等价于 num = num + 3num <<= 2 等价于 num = num << 2

  1. 逗号操作符:在 Go 语言中,逗号操作符用于分隔多个表达式,通常在 for 循环的初始化和步进部分使用。例如:
package main

import "fmt"

func main() {
    for i, j := 0, 10; i < 5; i, j = i+1, j-1 {
        fmt.Printf("i: %d, j: %d\n", i, j)
    }
}

这里逗号操作符用于初始化多个变量 ij,以及在每次循环结束时更新 ij

优先级冲突与解决

有时候,在复杂的表达式中,操作符的优先级可能会导致混淆。例如:

package main

import "fmt"

func main() {
    result := 2 + 3 * 4 / 2 % 3 << 2 & 5
    fmt.Println(result)
}

在这个表达式中,按照优先级顺序,先计算 3 * 4 得 12,再 12 / 2 得 6,6 % 3 得 0,0 << 2 得 0,0 & 5 得 0,最后加上 2,结果为 2。

为了避免混淆,可以使用括号来明确表达式的计算顺序,这样代码的可读性会大大提高。比如上面的表达式可以写成:

package main

import "fmt"

func main() {
    result := 2 + ((3 * 4 / 2 % 3) << 2 & 5)
    fmt.Println(result)
}

这样就清晰地展示了每一步的计算顺序。

优先级在复杂表达式中的应用

在实际编程中,经常会遇到复杂的表达式,需要综合运用多种操作符。例如,在一个判断用户权限的逻辑中:

package main

import "fmt"

func main() {
    userRole := "admin"
    hasPermission := true
    isActive := true
    canAccess := (userRole == "admin" || hasPermission) && isActive
    fmt.Println(canAccess)
}

这里先判断 userRole == "admin"hasPermission 是否为真,然后再与 isActive 进行逻辑与操作。如果不按照正确的优先级,结果可能会出错。

与其他语言优先级的对比

与 C 和 C++ 语言相比,Go 语言的操作符优先级有一些相似之处,但也有不同。例如,在 C 和 C++ 中,++-- 操作符的优先级非常高,而在 Go 语言中没有 ++-- 作为操作符的用法(它们是语句)。另外,C 和 C++ 中指针相关操作符的优先级规则在 Go 语言中也有不同的表现,Go 语言通过 *& 操作符来进行指针取值和取地址,其优先级遵循一元操作符的规则。

与 Python 相比,Python 的操作符优先级相对简单明了,且没有像 C 系语言那样复杂的位操作符优先级层次。Go 语言的优先级规则虽然相对复杂,但对于熟悉 C 系语言的开发者来说,有一定的继承性,便于理解和掌握。

总结操作符优先级的重要性

正确理解和运用 Go 语言的操作符优先级,能够让开发者编写出逻辑正确、高效且易于维护的代码。在复杂的表达式中,合理使用括号来明确优先级,可以避免潜在的错误,提高代码的可读性。同时,与其他语言优先级的对比,有助于开发者更好地掌握 Go 语言的特性,避免在跨语言开发中出现混淆。通过不断实践和对优先级规则的深入理解,开发者可以更加熟练地运用 Go 语言进行编程。