北屋教程网

专注编程知识分享,从入门到精通的编程学习平台

Go 语言运算符与表达式详解(go语言示例)

Go 语言运算符与表达式详解

Go 语言提供了丰富的运算符和表达式类型,用于执行各种计算和逻辑操作。下面我将全面介绍 Go 中的运算符和表达式系统。

一、运算符分类

1. 算术运算符

运算符

描述

示例

备注

+

加法

a + b

也可用于字符串连接

-

减法

a - b


*

乘法

a * b


/

除法

a / b

整数除法会截断小数部分

%

取模

a % b

仅用于整数

++

自增

a++

只有后置形式,不是表达式

--

自减

a--

只有后置形式,不是表达式

特殊案例

fmt.Println(5 / 2)   // 2 (整数除法)
fmt.Println(5 / 2.0) // 2.5 (浮点除法)
fmt.Println(10 % 3)  // 1

2. 关系运算符

运算符

描述

示例

==

等于

a == b

!=

不等于

a != b

<

小于

a < b

<=

小于等于

a <= b

>

大于

a > b

>=

大于等于

a >= b

注意:比较运算符返回 bool 值

3. 逻辑运算符

运算符

描述

示例

短路特性

&&

逻辑与

a && b

左假则右不计算

`


`

逻辑或

!

逻辑非

!a


短路示例

func isEven(n int) bool {
    fmt.Println("called")
    return n%2 == 0
}

if false && isEven(2) { // isEven不会被调用
    // ...
}

4. 位运算符

运算符

描述

示例

说明

&

按位与

a & b

对应位都为1则为1

`

`

按位或

`a

^

按位异或

a ^ b

对应位不同则为1

&^

位清除

a &^ b

将b中1的位在a中置0

<<

左移

a << n

左移n位,低位补0

>>

右移

a >> n

右移n位,高位补符号位

位运算案例

a := 0b1010 // 10
b := 0b1100 // 12

fmt.Printf("%04b\n", a&b)   // 1000 (8)
fmt.Printf("%04b\n", a|b)   // 1110 (14)
fmt.Printf("%04b\n", a^b)   // 0110 (6)
fmt.Printf("%04b\n", a&^b)  // 0010 (2)
fmt.Printf("%04b\n", a<<2)   // 101000 (40)
fmt.Printf("%04b\n", b>>1)   // 0110 (6)

5. 赋值运算符

运算符

描述

示例

等价于

=

简单赋值

a = b


+=

加后赋值

a += b

a = a + b

-=

减后赋值

a -= b

a = a - b

*=

乘后赋值

a *= b

a = a * b

/=

除后赋值

a /= b

a = a / b

%=

取模赋值

a %= b

a = a % b

&=

位与赋值

a &= b

a = a & b

`

=`

位或赋值

`a

^=

位异或赋值

a ^= b

a = a ^ b

<<=

左移赋值

a <<= n

a = a << n

>>=

右移赋值

a >>= n

a = a >> n

6. 其他运算符

运算符

描述

示例

说明

&

取地址

&a

获取变量内存地址

*

指针解引用

*ptr

获取指针指向的值

<-

通道操作

ch <- x

发送或接收数据

:

切片/数组定义

[n:m]

切片操作

...

可变参数/展开

func(a ...int)

函数参数或切片展开

二、运算符优先级

从高到低排列:

优先级

运算符

1

() [] -> . ++ --

2

+ - ! ^ * & <-

3

* / % << >> & &^

4

+ - `

5

== != < <= > >=

6

&&

7

`

示例

a := 5 + 3 * 2   // 11 (乘法优先)
b := (5 + 3)*2 // 16 (括号优先)

三、表达式类型

1. 基本表达式

变量/常量引用

x := 42
y := x + 10

字面量表达式

3.14          // 浮点数字面量
"hello"       // 字符串字面量
[]int{1,2,3}  // 切片字面量

2. 组合表达式

算术表达式

area := width * height
avg := (a + b + c) / 3.0

逻辑表达式

if age >= 18 && hasLicense {
    // ...
}

位运算表达式

flags := read | write | execute
mask := flags &^ disable

3. 函数调用表达式

// 简单调用
sum := add(a, b)

// 方法调用
reader := bufio.NewReader(os.Stdin)
line, _ := reader.ReadString('\n')

// 延迟调用
defer file.Close()

4. 类型断言表达式

var i interface{} = "hello"
s, ok := i.(string)  // ok为true
n, ok := i.(int)     // ok为false

5. 选择表达式

结构体字段选择

type Point struct{X, Y int}
p := Point{1, 2}
x := p.X

方法选择

var buf bytes.Buffer
buf.WriteString("hello")

6. 索引表达式

数组/切片索引

arr := [3]int{1, 2, 3}
val := arr[1]  // 2

映射索引

m := map[string]int{"a": 1}
v, ok := m["a"] // v=1, ok=true

7. 切片表达式

s := []int{0,1,2,3,4}
s1 := s[1:3]   // [1,2]
s2 := s[:4]    // [0,1,2,3]
s3 := s[2:]    // [2,3,4]
s4 := s[:]     // [0,1,2,3,4]

8. 类型转换表达式

i := 42
f := float64(i)
s := string(rune(i)) // 注意:不是数字转字符串
b := []byte("hello")

四、特殊运算符详解

1. 位清除运算符 &^

作用:将右操作数中为1的位,在左操作数中对应位置0

示例

a := 0b10101111
b := 0b00001111
c := a &^ b  // 10100000 (160)

实际应用:权限系统

const (
    Read = 1 << iota  // 0001
    Write             // 0010
    Execute           // 0100
)

func revokePermission(current, perm int) int {
    return current &^ perm
}

perms := Read | Write  // 0011
perms = revokePermission(perms, Write) // 0001

2. 通道运算符 <-

发送数据

ch := make(chan int, 1)
ch <- 42  // 发送值到通道

接收数据

value := <-ch  // 从通道接收值

作为类型

var inChan <-chan int  // 只读通道
var outChan chan<- int // 只写通道

3. 指针运算符 * 和 &

取地址

x := 42
ptr := &x  // 获取x的地址

解引用

y := *ptr  // 获取ptr指向的值
*ptr = 100 // 修改ptr指向的值

五、运算符重载与限制

Go 不支持运算符重载,这是设计上的选择:

  • 保持代码清晰性
  • 避免滥用导致的复杂行为
  • 所有运算符行为都是固定的

替代方案

  1. 使用方法代替运算符重载
  2. type Vector struct{X, Y int} func (v Vector) Add(other Vector) Vector { return Vector{v.X + other.X, v.Y + other.Y} }
  3. 实现特定接口(如 Stringer)
  4. func (v Vector) String() string { return fmt.Sprintf("(%d,%d)", v.X, v.Y) }

六、表达式求值规则

1. 求值顺序

Go 保证:

  1. 赋值语句从左到右求值
  2. 函数参数和索引表达式从左到右求值
  3. 运算符优先级决定运算顺序

示例

a := 1
f := func() int { a++; return a }
b := a + f()  // 可能是2或3,取决于求值顺序

2. 短路求值

逻辑运算符 && 和 || 会短路:

func isEven(n int) bool {
    fmt.Println("called")
    return n%2 == 0
}

if false && isEven(2) { // isEven不会被调用
    // ...
}

七、实战应用案例

1. 位运算实现标志位

const (
    FlagA = 1 << iota  // 0001
    FlagB              // 0010
    FlagC              // 0100
    FlagD              // 1000
)

func setFlag(flags, flag int) int {
    return flags | flag
}

func clearFlag(flags, flag int) int {
    return flags &^ flag
}

func hasFlag(flags, flag int) bool {
    return flags&flag != 0
}

func main() {
    var flags int
    flags = setFlag(flags, FlagA|FlagC)
    fmt.Printf("%04b\n", flags) // 0101
    
    flags = clearFlag(flags, FlagA)
    fmt.Printf("%04b\n", flags) // 0100
    
    fmt.Println(hasFlag(flags, FlagB)) // false
    fmt.Println(hasFlag(flags, FlagC)) // true
}

2. 安全类型转换工具函数

func ToInt(s string, defaultValue int) int {
    if n, err := strconv.Atoi(s); err == nil {
        return n
    }
    return defaultValue
}

func ToFloat(s string, defaultValue float64) float64 {
    if f, err := strconv.ParseFloat(s, 64); err == nil {
        return f
    }
    return defaultValue
}

3. 表达式解析器

func calculate(a, b int, op string) (int, error) {
    switch op {
    case "+":
        return a + b, nil
    case "-":
        return a - b, nil
    case "*":
        return a * b, nil
    case "/":
        if b == 0 {
            return 0, errors.New("division by zero")
        }
        return a / b, nil
    default:
        return 0, fmt.Errorf("unknown operator %q", op)
    }
}

Go 语言的运算符和表达式系统设计简洁而强大,虽然不支持运算符重载等复杂特性,但通过合理的组合使用,完全可以满足各种编程需求。理解运算符的优先级和结合性,掌握各种表达式的用法,是编写高效 Go 代码的基础。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言