内容简介:Golang:语法
Golang也是有相当的一段历史了(学新东西总是慢人一步,好可怕),特点是:
- 跨平台
- 垃圾回收(毕业后一直在用有GC的语言)
- 编译快
为工业开发量身定做,语法感觉并没有那么完备(复杂)。从传统入门程序来看它大概是这个样子:
package main import ( "fmt" ) func main() { fmt.Print("Hello World!") }
下面来看一些细节,跟其他语言对比着学会快些。
基础类型
变量创建的第一种方式为(不知道学的哪门子编程语言的套路):
func main() { var a int fmt.Println(a) // 0 a = 1 fmt.Println(a) // 1 }
多个变量可以省一些var,合并起来一起声明:
func main() { var ( a int b int ) fmt.Println(a, b) // 0 0 }
多个同类型的则可以更简单一些,包括赋值:
func main() { var a, b int fmt.Println(a, b) // 0 0 a, b = 3, 4 fmt.Println(a, b) // 3 4 }
常量的玩法和变量差不多,比较有意思和特别的自增,感觉为了省代码已经伤心病狂:
func main() { const ( a = iota // 自增 b c ) fmt.Println(a, b, c) // 0 1 2 }
不一样的地方:
高级类型
数组和C里面的有点像,声明之后就有内存了,而且大小不能再变:
func main() { var a [10]int fmt.Println(a) // [0 0 0 0 0 0 0 0 0 0] b := [2][2]int{[2]int{1, 2}, [2]int{3, 4}} fmt.Println(b) // [[1 2] [3 4]] c := [...]int{1, 2, 3} fmt.Println(c) // [1 2 3] d := [2][2]int{{1, 2}, {3, 4}} fmt.Println(d) // [[1 2] [3 4]] }
大小不确定的可以使用slice(跟 Python 有点像:joy:):
func main() { a := [100]int{} fmt.Println(len(a[10:80])) // 70 fmt.Println(cap(a[10:80])) // 90 // 追加 b := make([]int, 0) b1 := append(b, 10) fmt.Println(b1) // [10] b2 := append(b1, 20, 30) fmt.Println(b2) // [10 20 30] b3 := append(b2, b2...) fmt.Println(b3) // [10 20 30 10 20 30] }
另一种超高频结构是map:
func main() { a := map[int]map[int]int{ 1: map[int]int{2: 3}, } fmt.Println(a) // map[1:map[2:3]] fmt.Println(a[1]) // map[2:3] }
不一样的地方:
- 在用数组赋值时,会进行拷贝,而不是设置指针(值传递)
- 多维数组的长度必须一致
自定义类型
没有了class、enum,只能用struct来搞定一切:
// 定义结构体 type Mutex struct { a string b int } // 定义类型上的方法 func (m *Mutex)Lock() {} func (m *Mutex)Unlock() {} // 定义新类型 type MyMutex1 Mutex // 别名,不会集成方法 type MyMutex2 struct{ Mutex } // 会继承方法 func main() { b := new(MyMutex2) b.Mutex.Lock() }
不一样的地方:
- 通过首字母大小写来控制权限
- 方法的声明和实现都放到结构体外面
控制与方法
控制语句变得更加灵活和“随意”,尝试将多行代码合并成一行:
func main() { // 可以赋值,注意变量的作用域 if a, b := 1, 2; a < b { fmt.Println(a, b) // 1 2 } // 大名鼎鼎的GOTO回来了 var a int = 1 Label: if a < 10 { a += 1 goto Label } fmt.Println(a) // 10 // 三种循环形式 for a := 1; a < 10; a += 1 { } for a < 9 { } for { break } // SWITCH的两种形式 switch { case a < 1: case a < 2: } switch "123" { case "123": fmt.Println("123") // 123 break case "23": } }
比较新的Java也在变得随意,一些不一样的地方:
- while、do-while不见了
- goto回来了
- 省略了一些括号(感觉多一些括号会结构更清晰些)
一直把函数也当做了结构控制的一种方式,定义形式和多值返回都跟Python像:
func test(i1int, i2 []string)(o1int, o2string) { i2[0] = "a" return 1, "2" } func main() { fmt.Println(test(1, []string{"abc"})) // 1 2 }
在方法中使用关键字defer来处理函数退出前的操作,按照LIFO的顺序执行(有点像finally的替代):
func test() { for i := 0; i < 5; i++ { defer fmt.Printf("%d ", i) } } func main() { test() // 4 3 2 1 0 }
相对复杂一些的逻辑可以用函数封装,有没有看到些JavaScript中闭包的影子:
func test() { defer func() { fmt.Println("finish!") }() } func main() { test() // finish! }
同时也可以将函数搞成个变量,当做参数、返回值什么的,跟普通的变量没啥区别了:
func main() { add := func(aint)int { return a + 1 } fmt.Println(add(1)) }
不一样的地方:
- 多值返回
- 没有了异常机制
错误处理
在Golang中使用“恐慌”机制代替了异常机制:
- panic:中断执行,不影响defer的处理,如果没有在本函数中没有恢复,会在调用方产生“恐慌”
- recover:“恐慌”修复,必须在defer中调用
举个栗子:
func test() { defer func() { if x := recover(); x != nil { fmt.Println(x) // 出错 } }() panic("出错") fmt.Println("继续执行") // 不会执行 } func main() { test() }
由于支持多值返回,所以错误的信息也经常可以顺带返回(而不是在方法结尾加个throws,感觉方便太多了,有点C的处理风格):
import ( "fmt" "errors" ) func test()(int, error) { return 1, errors.New("abc") } func main() { ret, err := test() fmt.Println(ret, err) }
不一样的地方:
- “错误”与“异常”分开两种方式进行处理,不用再管运行时异常什么的了
接口
接口的作用是定义函数的集合:
type MyInterface interface { Get() int Put(int) }
具体实现不用显式地implements、entend相应的接口(原理是什么样的?):
type MyImpl struct { value int } func (self *MyImpl)Get()int { return self.value } func (self *MyImpl)Put(valueint) { self.value = value } func test(i MyInterface) { i.Put(1) println(i.Get()) // 1 } func main() { var i MyInterface = new(MyImpl) test(i) }
要想获取接口具体是什么,可以在switch中使用type进行判断(只能在switch中用,比较奇怪的语法):
func main() { var i MyInterface = new(MyImpl) switch i.(type) { case MyInterface: println("got MyInterface!") break } }
另外一种可以在switch外面判断的方法:
func main() { var i interface{} = new(MyImpl) t, ok := i.(MyInterface) fmt.Println(t, ok) // &{0} true }
不一样的地方:
- 不需要显式地实现接口,但是这样会不会容易漏掉实现一些方法
反射
拿到一个空接口时我们是比较懵逼的,因为压根不知道它里面有什么东西,用Java的同学会想到reflect,Go也有而且用法也差不多:
func main() { var i interface{} = new(MyImpl) t := reflect.TypeOf(i) fmt.Println(t) // *main.MyImpl fmt.Println(t.Kind()) // ptr fmt.Println(t.Elem()) // main.MyImpl fmt.Println(t.Elem().FieldByName("value")) // {value main int 0 [0] false} true }
类似的可以通过反射来调用方法!
I/O
对文件的读写跟Java比较像,打开文件后直接读取字节:
import "os" func main() { buf := make([]byte, 1024) f, _ := os.Open("/etc/passwd") defer f.Close() for { n, _ := f.Read(buf) if n == 0 { break } os.Stdout.Write(buf[0:n]) } }
带有缓存的读写像是搞了一层装饰:
import ( "bufio" "os" ) func main() { buf := make([]byte, 1024) f, _ := os.Open("/etc/passwd") defer f.Close() r := bufio.NewReader(f) w := bufio.NewWriter(os.Stdout) defer w.Flush() for { n, _ := r.Read(buf) r.R if n == 0 { break } w.Write(buf[0:n]) } }
其他的关于网络的,并没有涉及到什么新语法,后面再专门仔细看吧。
并发编程
并行所使用的不是线程、进程、协程,这里不纠结底层的原理,想并行处理用 go 即可,跟调用方法没多少区别:
func test(wstring, secint) { time.Sleep(time.Duration(sec) * time.Second) fmt.Println(w, " is ready!") } func main() { go test("a", 2) go test("b", 1) fmt.Println("main") time.Sleep(time.Duration(5) * time.Second) // main // b is ready! // a is ready! }
在并发编程领域有一个观点是用消息传递代替共享内存,于是便有了chan(消息的管道):
var c chan int func test(wstring, secint) { time.Sleep(time.Duration(sec) * time.Second) c <- sec // 向 c 中写入数据 } func main() { c = make(chan int) go test("a", 2) go test("b", 1) fmt.Println(<-c) // 1 从c中读取数据 fmt.Println(<-c) // 2 从c中读取数据 }
默认的情况下管道是没有缓存的,也就是说:
在数据没有被读走时,写会被阻塞;在没有写入数据时,读会被阻塞;
创建带缓冲的管道的方法是:
c = make(chan int, 4)
管道不用了可以使用close关闭管道,于是读取时判断是否关闭的方法为:
if a, ok := <-c; ok { fmt.Println(a) }
当需要从多个管道中读取数据时可以使用select(有点像I/O中的玩法):
var c chan int var d chan int func main() { c = make(chan int, 4) d = make(chan int, 4) var i int for { select { case i = <-c: break case i = <-d: break } } }
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Swift语法快速入门(一)之 Swift基础语法
- 在ES6中使用扩展语法有什么好处?它与rest语法有什么不同?
- Python 基础语法
- go语法
- JPQL 语言语法
- reStructuredText简明语法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Using Google App Engine
Charles Severance / O'Reilly Media / 2009-5-23 / USD 29.99
With this book, you can build exciting, scalable web applications quickly and confidently, using Google App Engine - even if you have little or no experience in programming or web development. App Eng......一起来看看 《Using Google App Engine》 这本书的介绍吧!