1.2.3 运算符与表达式 #
运算符是编程语言的基本构建块,用于对数据进行各种操作。Go 语言提供了丰富的运算符,包括算术运算符、比较运算符、逻辑运算符、位运算符等。本节将详细介绍这些运算符的使用方法和注意事项。
算术运算符 #
1. 基本算术运算 #
package main
import "fmt"
func main() {
a, b := 15, 4
// 基本算术运算符
fmt.Printf("a = %d, b = %d\n", a, b)
fmt.Printf("加法: %d + %d = %d\n", a, b, a+b)
fmt.Printf("减法: %d - %d = %d\n", a, b, a-b)
fmt.Printf("乘法: %d * %d = %d\n", a, b, a*b)
fmt.Printf("除法: %d / %d = %d\n", a, b, a/b)
fmt.Printf("取模: %d %% %d = %d\n", a, b, a%b)
// 浮点数运算
x, y := 15.0, 4.0
fmt.Printf("\n浮点数运算:\n")
fmt.Printf("x = %.1f, y = %.1f\n", x, y)
fmt.Printf("除法: %.1f / %.1f = %.3f\n", x, y, x/y)
// 混合类型运算需要类型转换
var intVal int = 10
var floatVal float64 = 3.5
result := float64(intVal) + floatVal
fmt.Printf("混合运算: %d + %.1f = %.1f\n", intVal, floatVal, result)
}
2. 自增自减运算符 #
package main
import "fmt"
func main() {
// 自增自减运算符
i := 5
fmt.Printf("初始值: i = %d\n", i)
// 后置自增(Go 只支持后置)
i++
fmt.Printf("i++ 后: i = %d\n", i)
// 后置自减
i--
fmt.Printf("i-- 后: i = %d\n", i)
// 注意:Go 不支持前置自增自减
// ++i // 错误
// --i // 错误
// 自增自减是语句,不是表达式
j := 10
// k := j++ // 错误:不能作为表达式使用
// 正确的做法
k := j
j++
fmt.Printf("j = %d, k = %d\n", j, k)
// 在循环中的使用
fmt.Print("循环输出: ")
for n := 0; n < 5; n++ {
fmt.Printf("%d ", n)
}
fmt.Println()
}
3. 复合赋值运算符 #
package main
import "fmt"
func main() {
// 复合赋值运算符
a := 10
fmt.Printf("初始值: a = %d\n", a)
a += 5 // 等价于 a = a + 5
fmt.Printf("a += 5: a = %d\n", a)
a -= 3 // 等价于 a = a - 3
fmt.Printf("a -= 3: a = %d\n", a)
a *= 2 // 等价于 a = a * 2
fmt.Printf("a *= 2: a = %d\n", a)
a /= 4 // 等价于 a = a / 4
fmt.Printf("a /= 4: a = %d\n", a)
a %= 3 // 等价于 a = a % 3
fmt.Printf("a %%= 3: a = %d\n", a)
// 位运算复合赋值
b := 12 // 二进制: 1100
fmt.Printf("\n位运算复合赋值:\n")
fmt.Printf("初始值: b = %d (二进制: %04b)\n", b, b)
b &= 10 // 按位与,二进制: 1010
fmt.Printf("b &= 10: b = %d (二进制: %04b)\n", b, b)
b |= 5 // 按位或,二进制: 0101
fmt.Printf("b |= 5: b = %d (二进制: %04b)\n", b, b)
b ^= 3 // 按位异或,二进制: 0011
fmt.Printf("b ^= 3: b = %d (二进制: %04b)\n", b, b)
b <<= 1 // 左移
fmt.Printf("b <<= 1: b = %d (二进制: %04b)\n", b, b)
b >>= 2 // 右移
fmt.Printf("b >>= 2: b = %d (二进制: %04b)\n", b, b)
}
比较运算符 #
package main
import "fmt"
func main() {
// 数值比较
a, b := 10, 20
fmt.Printf("a = %d, b = %d\n", a, b)
fmt.Printf("a == b: %t\n", a == b) // 等于
fmt.Printf("a != b: %t\n", a != b) // 不等于
fmt.Printf("a < b: %t\n", a < b) // 小于
fmt.Printf("a <= b: %t\n", a <= b) // 小于等于
fmt.Printf("a > b: %t\n", a > b) // 大于
fmt.Printf("a >= b: %t\n", a >= b) // 大于等于
// 字符串比较(按字典序)
str1, str2 := "apple", "banana"
fmt.Printf("\n字符串比较:\n")
fmt.Printf("str1 = %s, str2 = %s\n", str1, str2)
fmt.Printf("str1 == str2: %t\n", str1 == str2)
fmt.Printf("str1 < str2: %t\n", str1 < str2)
fmt.Printf("str1 > str2: %t\n", str1 > str2)
// 布尔值比较
bool1, bool2 := true, false
fmt.Printf("\n布尔值比较:\n")
fmt.Printf("bool1 = %t, bool2 = %t\n", bool1, bool2)
fmt.Printf("bool1 == bool2: %t\n", bool1 == bool2)
fmt.Printf("bool1 != bool2: %t\n", bool1 != bool2)
// 指针比较
x, y := 42, 42
px, py := &x, &y
pz := &x
fmt.Printf("\n指针比较:\n")
fmt.Printf("px == py: %t (不同变量的地址)\n", px == py)
fmt.Printf("px == pz: %t (同一变量的地址)\n", px == pz)
fmt.Printf("*px == *py: %t (指向的值)\n", *px == *py)
}
逻辑运算符 #
package main
import "fmt"
func main() {
// 逻辑运算符
a, b := true, false
fmt.Printf("a = %t, b = %t\n", a, b)
// 逻辑与 (&&)
fmt.Printf("a && b: %t\n", a && b)
fmt.Printf("a && true: %t\n", a && true)
fmt.Printf("false && b: %t\n", false && b)
// 逻辑或 (||)
fmt.Printf("a || b: %t\n", a || b)
fmt.Printf("a || false: %t\n", a || false)
fmt.Printf("false || false: %t\n", false || false)
// 逻辑非 (!)
fmt.Printf("!a: %t\n", !a)
fmt.Printf("!b: %t\n", !b)
fmt.Printf("!!a: %t\n", !!a)
// 短路求值演示
fmt.Printf("\n短路求值演示:\n")
// 逻辑与的短路求值
if false && expensiveOperation() {
fmt.Println("这行不会执行")
}
// 逻辑或的短路求值
if true || expensiveOperation() {
fmt.Println("这行会执行,但 expensiveOperation 不会被调用")
}
// 复杂逻辑表达式
x, y, z := 5, 10, 15
fmt.Printf("\n复杂逻辑表达式:\n")
fmt.Printf("x = %d, y = %d, z = %d\n", x, y, z)
result1 := (x < y) && (y < z)
fmt.Printf("(x < y) && (y < z): %t\n", result1)
result2 := (x > y) || (y < z)
fmt.Printf("(x > y) || (y < z): %t\n", result2)
result3 := !(x == y) && (z > y)
fmt.Printf("!(x == y) && (z > y): %t\n", result3)
}
func expensiveOperation() bool {
fmt.Println("执行了昂贵的操作")
return true
}
位运算符 #
package main
import "fmt"
func main() {
// 位运算符演示
a, b := 12, 10 // a = 1100, b = 1010 (二进制)
fmt.Printf("a = %d (二进制: %04b)\n", a, a)
fmt.Printf("b = %d (二进制: %04b)\n", b, b)
// 按位与 (&)
and := a & b
fmt.Printf("a & b = %d (二进制: %04b)\n", and, and)
// 按位或 (|)
or := a | b
fmt.Printf("a | b = %d (二进制: %04b)\n", or, or)
// 按位异或 (^)
xor := a ^ b
fmt.Printf("a ^ b = %d (二进制: %04b)\n", xor, xor)
// 按位取反 (^) - 一元运算符
notA := ^a
fmt.Printf("^a = %d (二进制: %032b)\n", notA, uint32(notA))
// 左移 (<<)
leftShift := a << 2
fmt.Printf("a << 2 = %d (二进制: %08b)\n", leftShift, leftShift)
// 右移 (>>)
rightShift := a >> 1
fmt.Printf("a >> 1 = %d (二进制: %04b)\n", rightShift, rightShift)
// 位运算的实际应用
fmt.Printf("\n位运算实际应用:\n")
// 检查奇偶性
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
for _, num := range numbers {
if num&1 == 0 {
fmt.Printf("%d 是偶数\n", num)
} else {
fmt.Printf("%d 是奇数\n", num)
}
}
// 权限系统示例
fmt.Printf("\n权限系统示例:\n")
const (
READ = 1 << iota // 1 (001)
WRITE // 2 (010)
EXECUTE // 4 (100)
)
// 设置权限
var permission int = READ | WRITE // 3 (011)
fmt.Printf("初始权限: %d (二进制: %03b)\n", permission, permission)
// 检查权限
fmt.Printf("有读权限: %t\n", permission&READ != 0)
fmt.Printf("有写权限: %t\n", permission&WRITE != 0)
fmt.Printf("有执行权限: %t\n", permission&EXECUTE != 0)
// 添加权限
permission |= EXECUTE
fmt.Printf("添加执行权限后: %d (二进制: %03b)\n", permission, permission)
// 移除权限
permission &^= WRITE // 清除写权限
fmt.Printf("移除写权限后: %d (二进制: %03b)\n", permission, permission)
}
运算符优先级 #
package main
import "fmt"
func main() {
// 运算符优先级演示
fmt.Println("运算符优先级演示:")
// 算术运算符优先级
result1 := 2 + 3 * 4
result2 := (2 + 3) * 4
fmt.Printf("2 + 3 * 4 = %d\n", result1) // 14
fmt.Printf("(2 + 3) * 4 = %d\n", result2) // 20
// 比较和逻辑运算符优先级
a, b, c := 5, 10, 15
result3 := a < b && b < c
result4 := a < b || b > c && c > a
fmt.Printf("a < b && b < c = %t\n", result3)
fmt.Printf("a < b || b > c && c > a = %t\n", result4)
// 位运算符优先级
x := 6 // 110
y := 3 // 011
result5 := x & y | 1 // (x & y) | 1
result6 := x & (y | 1)
fmt.Printf("x & y | 1 = %d\n", result5) // 3
fmt.Printf("x & (y | 1) = %d\n", result6) // 2
// 复杂表达式
result7 := 1 + 2 * 3 > 5 && 4 < 8 || false
fmt.Printf("1 + 2 * 3 > 5 && 4 < 8 || false = %t\n", result7)
// 使用括号明确优先级
result8 := ((1 + 2) * 3 > 5) && (4 < 8) || false
fmt.Printf("((1 + 2) * 3 > 5) && (4 < 8) || false = %t\n", result8)
}
类型转换在表达式中的应用 #
package main
import (
"fmt"
"math"
)
func main() {
// 不同类型的运算需要类型转换
var intVal int = 10
var floatVal float64 = 3.5
var int32Val int32 = 20
// 错误:不能直接运算不同类型
// result := intVal + floatVal // 编译错误
// 正确:显式类型转换
result1 := float64(intVal) + floatVal
result2 := intVal + int(floatVal) // 注意:会截断小数部分
result3 := int64(intVal) + int64(int32Val)
fmt.Printf("float64(intVal) + floatVal = %.1f\n", result1)
fmt.Printf("intVal + int(floatVal) = %d\n", result2)
fmt.Printf("int64(intVal) + int64(int32Val) = %d\n", result3)
// 类型提升在表达式中的应用
var a int8 = 100
var b int8 = 50
// 小整数类型在运算时会提升为 int
sum := a + b // 结果是 int 类型
fmt.Printf("类型: %T, 值: %d\n", sum, sum)
// 溢出处理
var maxInt8 int8 = 127
var overflow int8 = maxInt8 + 1 // 溢出
fmt.Printf("溢出结果: %d\n", overflow)
// 安全的运算
if int(maxInt8)+1 > 127 {
fmt.Println("运算会导致 int8 溢出")
}
// 浮点数精度问题
var f1 float32 = 1.0000001
var f2 float32 = 1.0000002
fmt.Printf("float32 精度: %.10f\n", f1-f2)
var d1 float64 = 1.0000001
var d2 float64 = 1.0000002
fmt.Printf("float64 精度: %.10f\n", d1-d2)
}
表达式求值和副作用 #
package main
import "fmt"
func main() {
// 表达式求值顺序
fmt.Println("表达式求值顺序:")
i := 0
// 注意:Go 语言中函数参数的求值顺序是未定义的
result := add(increment(&i), increment(&i))
fmt.Printf("结果: %d, i的最终值: %d\n", result, i)
// 安全的做法:避免在同一表达式中多次修改同一变量
i = 0
a := increment(&i)
b := increment(&i)
result = add(a, b)
fmt.Printf("安全的结果: %d, i的最终值: %d\n", result, i)
// 短路求值的副作用
fmt.Println("\n短路求值的副作用:")
counter := 0
if false && incrementCounter(&counter) > 0 {
fmt.Println("这行不会执行")
}
fmt.Printf("counter (&&): %d\n", counter) // 0,因为短路求值
counter = 0
if true || incrementCounter(&counter) > 0 {
fmt.Println("这行会执行")
}
fmt.Printf("counter (||): %d\n", counter) // 0,因为短路求值
// 复杂表达式的求值
fmt.Println("\n复杂表达式求值:")
x, y, z := 1, 2, 3
result = complexExpression(x, y, z)
fmt.Printf("复杂表达式结果: %d\n", result)
}
func add(a, b int) int {
fmt.Printf("add(%d, %d)\n", a, b)
return a + b
}
func increment(ptr *int) int {
*ptr++
fmt.Printf("increment: %d\n", *ptr)
return *ptr
}
func incrementCounter(counter *int) int {
*counter++
fmt.Printf("incrementCounter: %d\n", *counter)
return *counter
}
func complexExpression(x, y, z int) int {
// 复杂表达式:包含多种运算符
return (x+y)*z - x*y + (z<<1) | (x^y)
}
实际应用示例 #
1. 数学计算器 #
package main
import (
"fmt"
"math"
)
// 计算器结构
type Calculator struct {
precision int
}
// 创建计算器
func NewCalculator(precision int) *Calculator {
return &Calculator{precision: precision}
}
// 基本运算
func (c *Calculator) Add(a, b float64) float64 {
return c.round(a + b)
}
func (c *Calculator) Subtract(a, b float64) float64 {
return c.round(a - b)
}
func (c *Calculator) Multiply(a, b float64) float64 {
return c.round(a * b)
}
func (c *Calculator) Divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("除数不能为零")
}
return c.round(a / b), nil
}
func (c *Calculator) Power(base, exponent float64) float64 {
return c.round(math.Pow(base, exponent))
}
func (c *Calculator) Sqrt(a float64) (float64, error) {
if a < 0 {
return 0, fmt.Errorf("负数没有实数平方根")
}
return c.round(math.Sqrt(a)), nil
}
// 四舍五入到指定精度
func (c *Calculator) round(value float64) float64 {
multiplier := math.Pow(10, float64(c.precision))
return math.Round(value*multiplier) / multiplier
}
// 复合运算
func (c *Calculator) QuadraticFormula(a, b, c_coeff float64) (float64, float64, error) {
discriminant := b*b - 4*a*c_coeff
if discriminant < 0 {
return 0, 0, fmt.Errorf("判别式小于零,无实数解")
}
sqrtDiscriminant := math.Sqrt(discriminant)
x1 := (-b + sqrtDiscriminant) / (2 * a)
x2 := (-b - sqrtDiscriminant) / (2 * a)
return c.round(x1), c.round(x2), nil
}
func main() {
calc := NewCalculator(3)
// 基本运算测试
fmt.Println("基本运算测试:")
fmt.Printf("10 + 3.5 = %.3f\n", calc.Add(10, 3.5))
fmt.Printf("10 - 3.5 = %.3f\n", calc.Subtract(10, 3.5))
fmt.Printf("10 * 3.5 = %.3f\n", calc.Multiply(10, 3.5))
if result, err := calc.Divide(10, 3.5); err != nil {
fmt.Printf("除法错误: %v\n", err)
} else {
fmt.Printf("10 / 3.5 = %.3f\n", result)
}
fmt.Printf("2^10 = %.3f\n", calc.Power(2, 10))
if result, err := calc.Sqrt(16); err != nil {
fmt.Printf("平方根错误: %v\n", err)
} else {
fmt.Printf("√16 = %.3f\n", result)
}
// 二次方程求解
fmt.Println("\n二次方程求解 (x² - 5x + 6 = 0):")
if x1, x2, err := calc.QuadraticFormula(1, -5, 6); err != nil {
fmt.Printf("求解错误: %v\n", err)
} else {
fmt.Printf("解: x1 = %.3f, x2 = %.3f\n", x1, x2)
}
}
2. 位操作工具 #
package main
import "fmt"
// 位操作工具
type BitUtils struct{}
// 检查第n位是否为1
func (bu BitUtils) IsBitSet(value uint32, position uint) bool {
return (value & (1 << position)) != 0
}
// 设置第n位为1
func (bu BitUtils) SetBit(value uint32, position uint) uint32 {
return value | (1 << position)
}
// 清除第n位(设为0)
func (bu BitUtils) ClearBit(value uint32, position uint) uint32 {
return value &^ (1 << position)
}
// 切换第n位
func (bu BitUtils) ToggleBit(value uint32, position uint) uint32 {
return value ^ (1 << position)
}
// 计算设置的位数
func (bu BitUtils) CountSetBits(value uint32) int {
count := 0
for value != 0 {
count += int(value & 1)
value >>= 1
}
return count
}
// 获取最低位的1
func (bu BitUtils) GetLowestSetBit(value uint32) uint32 {
return value & (-value)
}
// 检查是否为2的幂
func (bu BitUtils) IsPowerOfTwo(value uint32) bool {
return value != 0 && (value&(value-1)) == 0
}
// 下一个2的幂
func (bu BitUtils) NextPowerOfTwo(value uint32) uint32 {
if value == 0 {
return 1
}
value--
value |= value >> 1
value |= value >> 2
value |= value >> 4
value |= value >> 8
value |= value >> 16
return value + 1
}
// 权限管理系统
type Permission uint32
const (
PermissionRead Permission = 1 << iota
PermissionWrite
PermissionExecute
PermissionDelete
PermissionAdmin
)
func (p Permission) String() string {
var permissions []string
if p&PermissionRead != 0 {
permissions = append(permissions, "READ")
}
if p&PermissionWrite != 0 {
permissions = append(permissions, "WRITE")
}
if p&PermissionExecute != 0 {
permissions = append(permissions, "EXECUTE")
}
if p&PermissionDelete != 0 {
permissions = append(permissions, "DELETE")
}
if p&PermissionAdmin != 0 {
permissions = append(permissions, "ADMIN")
}
if len(permissions) == 0 {
return "NONE"
}
result := permissions[0]
for i := 1; i < len(permissions); i++ {
result += " | " + permissions[i]
}
return result
}
func main() {
bu := BitUtils{}
// 位操作演示
fmt.Println("位操作演示:")
var value uint32 = 12 // 1100
fmt.Printf("初始值: %d (二进制: %04b)\n", value, value)
// 检查位
for i := uint(0); i < 4; i++ {
fmt.Printf("第%d位: %t\n", i, bu.IsBitSet(value, i))
}
// 设置位
value = bu.SetBit(value, 0)
fmt.Printf("设置第0位后: %d (二进制: %04b)\n", value, value)
// 清除位
value = bu.ClearBit(value, 2)
fmt.Printf("清除第2位后: %d (二进制: %04b)\n", value, value)
// 切换位
value = bu.ToggleBit(value, 1)
fmt.Printf("切换第1位后: %d (二进制: %04b)\n", value, value)
// 计算设置的位数
fmt.Printf("设置的位数: %d\n", bu.CountSetBits(value))
// 2的幂检查
testValues := []uint32{1, 2, 3, 4, 8, 15, 16, 32}
fmt.Println("\n2的幂检查:")
for _, val := range testValues {
fmt.Printf("%d 是2的幂: %t\n", val, bu.IsPowerOfTwo(val))
}
// 权限管理演示
fmt.Println("\n权限管理演示:")
// 创建用户权限
var userPerm Permission = PermissionRead | PermissionWrite
fmt.Printf("用户权限: %s\n", userPerm)
// 检查权限
fmt.Printf("有读权限: %t\n", userPerm&PermissionRead != 0)
fmt.Printf("有删除权限: %t\n", userPerm&PermissionDelete != 0)
// 添加权限
userPerm |= PermissionExecute
fmt.Printf("添加执行权限后: %s\n", userPerm)
// 移除权限
userPerm &^= PermissionWrite
fmt.Printf("移除写权限后: %s\n", userPerm)
// 管理员权限
adminPerm := PermissionRead | PermissionWrite | PermissionExecute | PermissionDelete | PermissionAdmin
fmt.Printf("管理员权限: %s\n", adminPerm)
}
常见错误和注意事项 #
1. 整数溢出 #
package main
import (
"fmt"
"math"
)
func main() {
// 整数溢出问题
var maxInt8 int8 = 127
fmt.Printf("int8 最大值: %d\n", maxInt8)
// 溢出导致回绕
maxInt8++
fmt.Printf("溢出后: %d\n", maxInt8) // -128
// 安全的溢出检查
func safeAdd(a, b int8) (int8, error) {
if a > 0 && b > 0 && a > math.MaxInt8-b {
return 0, fmt.Errorf("正溢出")
}
if a < 0 && b < 0 && a < math.MinInt8-b {
return 0, fmt.Errorf("负溢出")
}
return a + b, nil
}
if result, err := safeAdd(100, 50); err != nil {
fmt.Printf("加法溢出: %v\n", err)
} else {
fmt.Printf("安全加法结果: %d\n", result)
}
}
2. 浮点数比较 #
package main
import (
"fmt"
"math"
)
func main() {
// 浮点数精度问题
a := 0.1 + 0.2
b := 0.3
fmt.Printf("0.1 + 0.2 = %.17f\n", a)
fmt.Printf("0.3 = %.17f\n", b)
fmt.Printf("相等吗? %t\n", a == b) // false!
// 正确的浮点数比较
const epsilon = 1e-9
func floatEqual(x, y, epsilon float64) bool {
return math.Abs(x-y) < epsilon
}
fmt.Printf("近似相等吗? %t\n", floatEqual(a, b, epsilon))
// 相对误差比较
func floatEqualRel(x, y, relativeEpsilon float64) bool {
if x == y {
return true
}
diff := math.Abs(x - y)
largest := math.Max(math.Abs(x), math.Abs(y))
return diff <= relativeEpsilon*largest
}
fmt.Printf("相对误差比较: %t\n", floatEqualRel(a, b, 1e-9))
}
3. 运算符优先级陷阱 #
package main
import "fmt"
func main() {
// 位运算符优先级陷阱
x := 6
y := 3
// 错误的理解
result1 := x & y == 0 // 实际上是 x & (y == 0)
fmt.Printf("x & y == 0: %t (错误的理解)\n", result1)
// 正确的写法
result2 := (x & y) == 0
fmt.Printf("(x & y) == 0: %t (正确的写法)\n", result2)
// 逻辑运算符优先级
a, b, c := true, false, true
// 可能引起混淆的表达式
result3 := a || b && c // 实际上是 a || (b && c)
result4 := (a || b) && c
fmt.Printf("a || b && c: %t\n", result3)
fmt.Printf("(a || b) && c: %t\n", result4)
// 建议:使用括号明确优先级
fmt.Println("建议使用括号明确表达意图")
}
小结 #
本节详细介绍了 Go 语言的运算符和表达式,主要内容包括:
运算符类型 #
- 算术运算符:+, -, _, /, %, ++, –, +=, -=, _=, /=, %=
- 比较运算符:==, !=, <, <=, >, >=
- 逻辑运算符:&&, ||, !
- 位运算符:&, |, ^, «, », &^
重要概念 #
- 运算符优先级:理解不同运算符的优先级顺序
- 短路求值:逻辑运算符的短路特性
- 类型转换:不同类型间的运算需要显式转换
- 溢出处理:注意整数运算的溢出问题
最佳实践 #
- 使用括号明确表达式的优先级
- 注意浮点数比较的精度问题
- 避免在表达式中产生副作用
- 合理使用位运算符进行高效操作
掌握运算符和表达式的使用是编程的基础技能,为后续学习控制结构和函数奠定了重要基础。
练习题:
- 编写程序演示各种运算符的优先级
- 实现一个安全的整数运算库,包含溢出检查
- 创建一个位操作工具类,实现常用的位操作功能
- 编写一个表达式求值器,支持基本的数学运算
- 实现一个权限管理系统,使用位运算管理用户权限