Python 程序员的 Golang 学习指南(III): 入门篇
来源:互联网 发布:电脑显示器改网络电视 编辑:程序博客网 时间:2024/05/22 17:32
基础语法
类型和关键字
- 类型
// 基础类型布尔类型: 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 int b bool)// 同时给多个变量赋值a, b := 2, true
操作符
+ & += &= && == != ( )- | -= |= || < <= [ ]* ^ *= ^= <- > >= { }/ << /= <<= ++ = := , ;% >> %= >>= -- ! ... . : &^ &^=
控制结构
Go 语言支持如下的几种流程控制语句:
- 条件语句,对应的关键字为 if、else 和 else if;
- 选择语句,对应的关键字为 switch、case 和 select;
- 循环语句,对应的关键字为 for 和 range;
- 跳转语句,对应的关键字为 goto。
值得一提的是,Go 语言并不支持 do 或者 while 关键字,而是对 for 关键字做了增强,以实现类似的效果,如下:
for { // 实现无限循环,慎用!}
常用内置函数
- len:计算(字符串,数组或者切片,map)长度
- cap:计算(数组或者切片,map)容量
- close:关闭通道
- append:追加内容到切片
- copy:拷贝数组/切片内容到另一个数组/切片
- delete:用于删除 map 的元素
array, slice 和 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 := 5 a := func() func() { i := 10 return func() { fmt.Printf("i, j: %d, %d\n", i, j) } }() a() j *= 2 a()}
程序输出如下:
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 string Middle string Last string}
同样也可以定义基础类型:
type SimpleName string
还能给任意类型定义方法:
func (s SimpleName) String() string { return string(s) }// 或者func (s string) NoWay()
Golang VS Python
最后我们通过几个例子来比较一下 Golang 与 Python 的一些基本用法,如下:
生成器(Generator)
- Python 版本
def fib(n): a, b = 0, 1 for i in range(n): a, b = b, a + b yield afor x in fib(10): print xprint 'done'
- Golang 版本
package mainimport "fmt"func fib(n int) chan int { c := make(chan int) go func() { a, b := 0, 1 for i := 0; i < n; i++ { a, b = b, a+b c <- a } close(c) }() return c}func main() { for x := range fib(10) { fmt.Println(x) }}
装饰器(Decorator)
- Python 版本
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_required def 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()
- Golang 版本
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)}
猴子补丁(Monkey patching)
- Python 版本
import urllibdef say_hi(usr): if auth(usr): print 'Hi, %s' % usr else: print 'unknown user %s' % usrdef auth(usr): try: auth_url = 'localhost' r = urllib.urlopen(auth_url + '/' + usr) return r.getcode() == 200 except: return Falsedef sayhitest(): # Test authenticated user globals()['auth'] = lambda x: True say_hi('John') # Test unauthenticated user globals()['auth'] = lambda x: False say_hi('John')if __name__ == '__main__': sayhitest()
- Golang 版本
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
Go 语言中的 Array,Slice,Map 和 Set
https://golang.org/doc/faq#overloading
Go 语言的错误处理机制是一个优秀的设计吗? - 异常处理
https://talks.golang.org/2013/go4python.slide
Golang 系列教程
Python 程序员的 Golang 学习指南(II): 开发环境搭建
Python 程序员的 Golang 学习指南(I): Go 之初体验
欢迎交流,可以通过我的 Blog 找到我:startover's blog
- Python 程序员的 Golang 学习指南(III): 入门篇
- C和Python程序员的JavaScript学习指南(译)
- Java程序员的Golang入门指南(上)
- Java程序员的Golang入门指南(下)
- C++程序员我的学习指南
- 给 程序员 的设计学习指南
- 给 程序员 的设计学习指南
- 给 程序员 的设计学习指南
- 给 程序员 的设计学习指南
- 给 程序员 的设计学习指南
- Python 学习指南
- Python学习指南
- springmvc学习指南-springmvc的CRUD入门
- Inventor 二次开发学习指南(入门到精通)
- 程序员的十层楼 III【Reprinted】
- python学习指南教程(更新完毕)
- 深度学习学习指南(Python版)
- Golang入门-----安装配置篇
- 说说PHP的autoLoad自动加载机制
- Android PullTorefreshScrollview回到顶部
- CLRS 16.1活动选择问题
- 【框架】[Spring]AOP拦截-三种方式实现自动代理
- 浅析去中心化的商业积分体系
- Python 程序员的 Golang 学习指南(III): 入门篇
- Java类初始化顺序
- PC鼠标拖动滑块 转变为 手机手指滑动滑块
- Linux cat 终端 中文 乱码
- 一个简单的C++加密,解密文件程序
- 再谈区块链在积分领域的应用
- [160902][Android]Android中数据的存储方式
- 腾讯模拟笔试题——回形数
- 跨平台PowerShell如何远程管理Linux/Mac/Windows?