原文发布于我的站点: GitDiG.com, 原文连接: Go 编程:那些隐晦的操做符
本篇做为 Go 编程“边角料”的最后一篇,主要针对 Go 语言提供的操做符进行一次总结。恰好回应上篇一位读者关于表达式是否要加'.'的问题作个回复。html
在 Go 语言中,一共提供了47个操做符,包括标点符号。摘自官方文档,分别是:git
+ & += &= && == != ( ) - | -= |= || < <= [ ] * ^ *= ^= <- > >= { } / << /= <<= ++ = := , ; % >> %= >>= -- ! ... . : &^ &^=
除以上操做符之外,在 Go 语言中还有一个特殊的符号 _
, 以及一个非 Go 语言操做符的特殊字节?
。github
刨去一些经常使用的操做符,对其中较隐晦操做符作个简单的备注,方便不时之需。
就隐晦自己而言能够划分为两类:golang
上文中的 47 个操做符,一个个看下来,真正隐晦的符号基本上都是位运算操做符或相关操做符。
之因此隐晦,由于位运算在大部分开发人员的平常开发中属于很是规操做,由于运用得少,而增长了其陌生感。不妨简单罗列一下:sql
& bitwise AND integers | bitwise OR integers ^ bitwise XOR integers &^ bit clear (AND NOT) integers << left shift integer << unsigned integer >> right shift integer >> unsigned integer
写个简单的例子, 强化记忆:编程
package main import "fmt" func main(){ fmt.Printf("AND: a(%b) & b(%b) = (%b)\n", 4, 5, (4 & 5)) fmt.Printf("OR: a(%b) | b(%b) = (%b)\n", 4, 5, (4 | 5)) fmt.Printf("XOR: a(%b) ^ b(%b) = (%b)\n", 4, 5, (4 ^ 5)) fmt.Printf("AND NOT: a(%b) &^ b(%b) = (%b)\n", 4, 5, (4 &^ 5)) fmt.Printf("Left Shift: a(%b) << 1 = (%b)\n", 5, (5 << 1)) fmt.Printf("Right Shift: a(%b) >> 1 = (%b)\n", 5, (5 >> 1)) }
输出的结果是:c#
AND: a(100) & b(101) = (100) OR: a(100) | b(101) = (101) XOR: a(100) ^ b(101) = (1) AND NOT: a(100) &^ b(101) = (0) Left Shift: a(101) << 1 = (1010) Right Shift: a(101) >> 1 = (10)
位操做符并不难,之因此隐晦,主要是实际运用的少致使的。其中,XOR 运算有个特色:若是对一个值连续作两次 XOR,会返回这个值自己。XOR 的这个特色,使得它能够用于信息的加密。阮一峰这篇文章XOR 加密简介很好读。数组
与位运算符相关的符号,有:ide
<<= >>= &= ^= |=
其功能与+=
是同样的,即 a += 1
等同于 a = a + 1
。函数
另外一类操做符,看似很是简单,但因其在不一样应用场景下产生了不一样功能效果,致使在使用上的陌生。
符号 '_', 又称为空标识符(Blank identifier)。它有两种使用场景,不一样场景提供的功能是不一样的.
此时符号 '_', 功能与 /dev/null
相似,只负责接收值并直接丢弃,没法取回。
ar := [10]int{1,2,3,4,5,6,7,8,9,0} for _, v := range ar { println(v) }
常规状况下,包引用格式是这样的:
package YourPackage import "lib/math" //math.Sin import m "lib/math" //m.Sin import . "lib/math" //Sin
具体语法意义不解释了。如今看看 '_' 在包引入中的功能。
import _ "the/third/pkg"
此时引入的第三方包"the/third/pkg"
,若是引入的结果是一个空标识符'_'。按其空标识符的原始意义,就是对于使用方而言,没有任何意义,由于没法使用被引入包中任何变量或是函数。
可是,这种引用有一个反作用,就是:会对第三方包进行编译而且执行初始化func init()
操做.这一功能,对于某些引用方就很是有用。
因此当咱们研究一些开源代码时,看到相似的引用import _ "the/third/pkg"
时,直接跳到引入包的init
函数,就能够创建起内在逻辑。不妨看一下github.com/golang/protobuf/protoc-gen-go/link_grpc.go
的代码, 这就是grpc
插件注册到protoc-gen-go
的地方。
package main import _ "github.com/golang/protobuf/protoc-gen-go/grpc"
符号 '.' 常规状况下是做为选择器的在使用。如:
//直接选择属性名或函数名 x.FieldName x.FunctionName
还能够作为包引用使用,如上节。
import . "lib/math" //Sin
它的做用有点相似当前目录符'.'的意思了,简化掉了包引用的相对路径。
还有一个用法,即类型断言(type assertion)。
//类型断言: 类型必须用'()'括起来 v, ok := x.(T)
做为类型断言时,类型必须用'()'括起来,防止和选择器功能混淆。类型断言与类型转换须要区分一下。
//类型转换: 变量必须用'()'括起来 v := T(x)
区别:
x
只要是一个能够转换成目标类型的变量便可。失败时代码没法编译经过。x
必须与目标类型一致。若是失败,返回bool
参数标识。符号 '...' 主要用于不定参数与切片打散功能。很是简单,备注一下。
不定参数
import "fmt" func Foo(args ...interface{}) { for _, arg := range args { fmt.Println(arg) } }
切片打散
args := []interface{}{1, false, "hello"} Foo(args...)
数组长度
[...]int{1,2,4}
不少语言都支持符号 '?', 可是在 Go 语言中并它不属于系统操做符, 虽然在 Go 代码中常常会碰到符号 '?'。在语言级别符号 '?' 没有任何语法意义,只是一个常规的字节。
常见使用场景是作为 SQL 语句的替换符使用。如:
import "database/sql" id := 47 result, err := db.ExecContext(ctx, "UPDATE balances SET balance = balance + 10 WHERE user_id = ?", id) if err != nil { log.Fatal(err) }
其中的符号 '?' 仅仅与依赖包database/sql
有关,与 Go 语言自己无关。在database/sql
包中,字符 '?' 能够将任意类型参数变量替换转义成 SQL 字符串合适的类型值。
以上收集的操做符仅仅是个简单的小结,可能更多的应用场景没有关注到,欢迎指正。