虽然Go已经不算是一个很新的语言了,但是现在非常地火!一般来说语言本身没有什么好讲究的,能快速编程、少点坑就算是一门好的语言了。但是,如果语言火了之后,其周围的工具发展起来之后,能用它做的事情就太多了~
因为我仅仅打算在ubuntu上面进行golang的开发,所以其他的系统后面用过了再来补充!配置来说相当容易:
下面就开始GOLANG的学习。
按照惯例,来看Hello World代码:
package main import "fmt" func main(){ fmt.Println("Hello World"); }
使用go run hello.go即可执行,也可以使用go build hello.go打包完成之后在运行,所有的命令作用如下:
命令 | 作用 |
---|---|
build | 用于测试编译 |
clean | 移除当前源码包里面编译生成的文件 |
env | 环境变量 |
fix | 修复以前老版本的代码到新版本 |
fmt | 代码格式化 |
generate | |
get | 动态获取远程代码包的,目前支持的有BitBucket、GitHub、Google Code和Launchpad |
install | 生成结果文件(可执行文件或者.a包),把编译好的结果移到$GOPATH/pkg或者$GOPATH/bin |
list | 列出当前全部安装的package |
run | 编译并运行Go程序 |
test | 自动读取源码目录下面名为*_test.go的文件,生成并运行测试用的可执行文件 |
tool | 运行对应的工具类 |
version | 版本号 |
码代码最基本的是变量和常量,在Go中的定义方法如下:
var a string = "initial" /* 变量 */ const s string = "initial" /* 常量 */
另外一些基本的控制结构也基本一致,简单来看就是省略了不少的括号:
// FOR for i <= 3 for i := 1; i <= 3; i++ for // IF if 8%4 == 0 if num := 9; num < 0 // SWITCH switch time.Now().Weekday() { case time.Saturday, time.Sunday: default: }
Go中的集合用起来感觉跟Python中的有点像:
// ARRAY:数组 var a [5]int b := [5]int{1, 2, 3, 4, 5} var c [2][3]int // SLICES:跟数组很像,不过区间操作非常方便 s := make([]string, 10) l := s[2:5] l := s[2:] l := s[:5] // RANGE:更方便地遍历,数组的话返回下标和值,MAP返回KEY、VALUE for _,num := nums { sum += num; } // MAP:这个没什么好说的 m := make(map[string]int) m["a"] = 1 m["b"] = 2
在Go中定义方法也是比较奇葩的语法,用过的其他语言大部分把返回值写在前面,而它是写在后面,不过应该也没有谁优谁劣,而且在Go中方法可以返回多个值(尤其是在后面会用来返回错误):
func vals() (int, int) {// 普通函数:a, b := vals() return 1, 2; } func sum(nums ...int) {// 可变参数:sum(1, 2) sum(1, 2, 3) } func zeroptr(iptr *int) {// 参数类型为指针 *iptr = 0 } func intSeq() func() int {// 闭包 i := 0 return func() int { i += 1 return i } }
在Go中所有的面向对象就是struct了,是不是感觉有点简单?或者有点low?另外在Go中定义了一个奇葩的interface,感觉有点像是一个方法的集合:
type method interface { output(); } type person struct { name string age int } func (p *person) output(){// 定义方法,再次吐槽:是不是跟Python很像 fmt.Println(p.name, p.age); } func f(m method) { // 为不同对象定义相同的方法,用这个来实现泛型的话,额~~ fmt.Println(m); m.output(); } func f1(arg int) (int, error) { return -1, errors.New("i can't work!"); // 返回错误 } // 调用方法 fmt.Println(person{"Bob", 20}) fmt.Println(person{name: "Alice", age: 30})
在Go中比较吸引人的应该就是goroutines,面向并发的语言自然要最大程度的简化对应的代码才算合格。在Go中任意一个方法都可以使用go这个关键字来当做一个协程进行处理:
go func(“abc”)
仅仅这样是不够的,在Go中又提供了channel用来做消息传递,这样:
这两种方式在Go里面就凑齐了,另外select也大大简化了IO时候的操作,代码减了多少并不重要,关键是代码与其含义更加地贴近:
messages := make(chan string) messages := make(chan string, 2) messages <- "buffered" // 写入 msg := <-messages // 读取 select { case msg := <-messages: fmt.Println("received message", msg) default:// 这样就不会阻塞了 fmt.Println("no message received") }
总是感觉select与switch很像,不仅仅是写法上面,另外连TimeOut的写法能很简单、粗暴地搞定:
select { case res := <-c1: fmt.Println(res) case <-time.After(time.Second * 1): fmt.Println("timeout 1") }
用这种方式能设置延迟,在需要重复的场景下可以用ticker := time.NewTicker(time.Millisecond * 500)来解决。
在Go语言中不支持传统的try-catch-finally这种异常机制,因为Go的设计者认为可能程序员经常会滥用,所以在大部分的情况都通过返回多个值、其中一个为ERROR的办法来处理,只有在真正异常的情况下才使用Go的Exception机制:
来看简单的例子:
func f() (result int) {// 返回值为1,只有defer执行后才有效 defer func() { result++ }() return 0; } panic("problem");// 在这个地方程序就挂掉了 func a(){ panic("a---error"); } func b(){ panic("b---error"); } func(){ def func(){ if r:= recover(); r != nil { log.Printf("caught: %v", r); } } }
用recover的方法有点像缩水版的try-catch,最后,在Go中居然支持goto,虽然我觉得goto还是挺好用的。
简单把Go的语法过了一遍,总体的感觉就是简单、面向工程开发,没有很多的废话,也没有太多学术上很有用、工程上用的不多的细节。基本语法的例子都可以在这里找到。