@startover
2016-09-14T13:27:40.000000Z
字数 5176
阅读 2014
Golang
// 基础类型布尔类型: bool整型: int8,uint8,int16,uint16,int32,uint32,int64,uint64,int,rune,byte,complex128, complex64,其中,byte 是 int8 的别名浮点类型: float32 、 float64复数类型: complex64 、 complex128字符串: string字符类型: rune(int32的别名)错误类型: error// 复合类型指针(pointer)数组(array)切片(slice)字典(map)通道(chan)结构体(struct)接口(interface)
break default func interface selectcase defer go map structchan else goto package switchconst fallthrough if range typecontinue for import return var
Go 同其他语言不同的地方在于变量的类型在变量名的后面,不是 int a,而是 a int。至于为什么这么定义,Go 的官方博客有给出解释,有兴趣的可以参考下。
变量定义语法如下:
var a inta = 2// 或者a := 2// 同时定义多个变量var (a intb bool)// 同时给多个变量赋值a, b := 2, true
+ & += &= && == != ( )- | -= |= || < <= [ ]* ^ *= ^= <- > >= { }/ << /= <<= ++ = := , ;% >> %= >>= -- ! ... . :&^ &^=
Go 语言支持如下的几种流程控制语句:
1. 条件语句,对应的关键字为 if、else 和 else if;
2. 选择语句,对应的关键字为 switch、case 和 select;
3. 循环语句,对应的关键字为 for 和 range;
4. 跳转语句,对应的关键字为 goto。
值得一提的是,Go 语言并不支持 do 或者 while 关键字,而是对 for 关键字做了增强,以实现类似的效果,如下:
for {// 实现无限循环,慎用!}
len:计算(字符串,数组或者切片,map)长度cap:计算(数组或者切片,map)容量close:关闭通道append:追加内容到切片copy:拷贝数组/切片内容到另一个数组/切片delete:用于删除 map 的元素
// arraya := [3]int{ 1, 2, 3 } // 等价于 a := [...]int{ 1, 2, 3 }// slices := make([]int , 3) // 创建一个长度为 3 的 slices := append(s, 1) // 向 slice 追加元素s := append(s, 2)// mapm := make(map[string]int) // 使用前必须先初始化m["golang"] = 7
关于 array, slice 和 map 的更多惯用法,有一篇文章介绍的挺详细,有兴趣的可以看看。
Go 语言的函数有如下特性:
由于 Go 语言不支持函数重载(具体原因见 Go Language FAQ),但我们可以通过不定参数实现类似的效果。
func myfunc(args ...int) {// TODO}// 可通过如下方式调用myfunc(2)myfunc(1, 3, 5)
与 C、C++ 和 Java 等开发语言的一个极大不同在于,Go 语言的函数或者成员的方法可以有多
个返回值,这个特性能够使我们写出比其他语言更优雅、更简洁的代码。
func (file *File) Read(b []byte) (n int, err error)// 我们可以通过下划线(_)来忽略某个返回值n, _ := f.Read(buf)
匿名函数是指不需要定义函数名的一种函数实现方式,它并不是一个新概念,最早可以回溯
到 1958 年的 Lisp 语言。但是由于各种原因,C 和 C++ 一直都没有对匿名函数给以支持,其他的各
种语言,比如 JavaScript、C# 和 Objective-C 等语言都提供了匿名函数特性,当然也包含Go语言。
匿名函数由一个不带函数名的函数声明和函数体组成,如下:
func(a, b int) bool {return a < b}
匿名函数可以直接赋值给一个变量或者直接执行:
f := func(a, b int) bool {return a < b}func(a, b int) bool {return a < b}(3, 4) // 花括号后直接跟参数列表表示函数调用
闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者
任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含
在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定的计算环
境(作用域)。
Go 的匿名函数就是一个闭包。我们来看一个例子:
package mainimport "fmt"func main() {j := 5a := func() func() {i := 10return func() {fmt.Printf("i, j: %d, %d\n", i, j)}}()a()j *= 2a()}
程序输出如下:
i, j: 10, 5i, j: 10, 10
Go 语言追求简洁优雅,所以,Go 语言不支持传统的 try...catch...finally 这种异常,因为 Go 语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。在 Go 语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下,也就是说,遇到真正的异常的情况下(比如除数为0了),才使用 Go 中引入的Exception处理:defer, panic, recover。
用法如下:
package mainimport "fmt"func main() {defer func() {fmt.Println("recovered:", recover())}()panic("not good")}
关于 Go 语言的错误处理机制和传统的 try...catch...finally 异常机制孰优孰劣,属于仁者见仁,智者见智,这里不做赘速。有兴趣的同学可以去看看知乎上的讨论:Go 语言的错误处理机制是一个优秀的设计吗?。
Python 推崇“一切皆对象”,而在 Go 语言中,类型才是一等公民。
我们可以这样定义一个结构体:
type Name struct {First stringMiddle stringLast string}
同样也可以定义基础类型:
type SimpleName string
还能给任意类型定义方法:
func (s SimpleName) String() string { return string(s) }// 或者func (s string) NoWay()
最后我们通过几个例子来比较一下 Golang 与 Python 的一些基本用法,如下:
def fib(n):a, b = 0, 1for i in range(n):a, b = b, a + byield afor x in fib(10):print xprint 'done'
package mainimport "fmt"func fib(n int) chan int {c := make(chan int)go func() {a, b := 0, 1for i := 0; i < n; i++ {a, b = b, a+bc <- a}close(c)}()return c}func main() {for x := range fib(10) {fmt.Println(x)}}
from urlparse import urlparse, parse_qsfrom BaseHTTPServer import HTTPServer, BaseHTTPRequestHandlerdef auth_required(myfunc):def checkuser(self):user = parse_qs(urlparse(self.path).query).get('user')if user:self.user = user[0]myfunc(self)else:self.wfile.write('unknown user')return checkuserclass myHandler(BaseHTTPRequestHandler):@auth_requireddef do_GET(self):self.wfile.write('Hello, %s!' % self.user)if __name__ == '__main__':try:server = HTTPServer(('localhost', 8080), myHandler)server.serve_forever()except KeyboardInterrupt:server.socket.close()
package mainimport ("fmt""net/http")var hiHandler = authRequired(func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hi, %v", r.FormValue("user"))},)func authRequired(f http.HandlerFunc) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {if r.FormValue("user") == "" {http.Error(w, "unknown user", http.StatusForbidden)return}f(w, r)}}func main() {http.HandleFunc("/hi", hiHandler)http.ListenAndServe(":8080", nil)}
import urllibdef say_hi(usr):if auth(usr):print 'Hi, %s' % usrelse:print 'unknown user %s' % usrdef auth(usr):try:auth_url = 'localhost'r = urllib.urlopen(auth_url + '/' + usr)return r.getcode() == 200except:return Falsedef sayhitest():# Test authenticated userglobals()['auth'] = lambda x: Truesay_hi('John')# Test unauthenticated userglobals()['auth'] = lambda x: Falsesay_hi('John')if __name__ == '__main__':sayhitest()
package mainimport ("fmt""net/http")func sayHi(user string) {if !auth(user) {fmt.Printf("unknown user %v\n", user)return}fmt.Printf("Hi, %v\n", user)}var auth = func(user string) bool {authURL := "localhost"res, err := http.Get(authURL + "/" + user)return err == nil && res.StatusCode == http.StatusOK}func testSayHi() {auth = func(string) bool { return true }sayHi("John")auth = func(string) bool { return false }sayHi("John")}func main() {testSayHi()}
相关链接:
https://blog.golang.org/gos-declaration-syntax
https://se77en.cc/2014/06/30/array-slice-map-and-set-in-golang/
https://golang.org/doc/faq#overloading
https://www.zhihu.com/question/27158146
https://talks.golang.org/2013/go4python.slide