1. var, const
定义变量和常量
var name string
var name string = "myName" //string 能够被自动推断, 可以省略
var name1, name2, name3 string = "name1", "name2", "name3" //string 能够被自动推断, 可以省略
var (
name = "myName"
age = 18
)
// := 简短声明, 只能用在函数内部
name1, name2, name3 := "name1", "name2", "name3"
2. package, import
定义包和引入包
包名按约定应使用小写字符
包中的函数或变量等, 首字母为大写时, 将被导入, 可使用; 首字母的大小写, 类似于 java 中的 public 和 private
package main
import "find-in-file/cmd"
// 多个包引入
import (
"bufio"
"fmt"
"log"
"os"
"strings"
)
// 别名
import (
"os"
myHomeDir "github.com/mitchellh/go-homedir"
"github.com/spf13/viper"
)
3. map
内置数据类型
4. func
定义函数
5. return, defer
函数的返回和延迟执行
defer 经常用于资源的释放, 会在 return 之前执行; 多个 defer 语句, 越后面的越先执行, 后入先出 ;
相比 java 中的 try-with-resources 更优雅
func test() {
f, err := os.Open(filename)
if err != nil {
panic(err)
}
defer f.Close()
// 针对文件f 的具体操作...
}
package main
import "fmt"
func main() {
a := test()
fmt.Println("a is", a, "after return")
}
func test() (r int) {
a := 0
fmt.Println("p1 a is", a)
defer func(a int) (r int){
fmt.Println("a is", a, "in defer")
return a + 1
}(a)
a = a +1
fmt.Println("p2 a is", a)
return a
}
//以下为执行结果
//p1 a is 0
//p2 a is 1
//a is 0 in defer
//a is 1 after return
6. type,struct
type 关键字用于定义类型
struct 表示为结构体类型, 是值类型, 赋值和传参会拷贝内容(区别于 java 语言)
type Person struct {
Name string
Age int
}
func main() {
p := Person{
Name: "张三",
Age: 20,
}
p.Age = 25
fmt.Println(p)
}
//匿名类型
type Person struct {
Name string
Attr struct{
age int
}
}
//嵌入组合
package main
import "fmt"
type Person struct {
Name string
Age int
}
type Worker struct {
Person
Name string
}
func main() {
p := Person{
Name: "张三",
Age: 18,
}
fmt.Printf("%v\n", p)
p.Age = 25
fmt.Printf("%v\n", p)
w := Worker{
Person: Person{
Name: "张三",
Age: 25,
},
Name: "建筑工人",
}
fmt.Printf("%v\n", w)
//当被嵌入结构中的某个字段与当前struct中已存在的字段同名时,
//编译器从外向内逐级查找所有层次的匿名字段,
//直到发现目标或者报错
fmt.Printf("%s\n", w.Name)
fmt.Printf("%s\n", w.Person.Name)
fmt.Printf("%d\n", w.Age)
}
//输出打印
//{张三 18}
//{张三 25}
//{{张三 25} 建筑工人}
//建筑工人
//张三
//25
7. interface
接口类型
//期中空接口, 非常常用, 即不需要实现任何方法,
//可以看fmt#Print 相关方法
package main
import "fmt"
type SaySomeThing interface {
Say()
}
type Human struct {
Name string
}
type Dog struct {
Name string
}
func (p *Human) Say() {
fmt.Println("哈哈哈")
}
func (d *Dog) Say() {
fmt.Println("汪汪汪")
}
func main() {
h := Human{
Name: "张三",
}
test(&h)
d := Dog{
Name: "二哈",
}
test(&d)
}
func test(canSay SaySomeThing) {
canSay.Say()
fmt.Println("使用接口成功调用")
}
9. for, break, continue, goto, range
循环控制语句
i := 1
for i <= 3 {
fmt.Println(i)
i = i + 1
}
for j := 7; j <= 9; j++ {
fmt.Println(j)
}
for {
fmt.Println("loop")
break
}
10. if, else
if num := 9; num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "has 1 digit")
} else {
fmt.Println(num, "has multiple digits")
}
11. switch, case, default, fallthrough
区别于 java , 每个 case 都可以理解为自动带了 break ;
如果想继续执行后面分支的代码, 则需 fallthrough ;
switch sExpr {
case expr1:
doSomeThing1()
case expr2:
doSomeThing2()
case expr3:
doSomeThing3()
default:
doDefault()
}
12. go
开启协程异步执行
package main
import (
"fmt"
"sync"
)
func main() {
wg := sync.WaitGroup{}
//异步干3件事
wg.Add(3)
go func() {
r := add(1, 2)
fmt.Println("r is", r)
wg.Done()
}()
go func() {
r := add(2, 3)
fmt.Println("r is", r)
wg.Done()
}()
go func() {
r := add(3, 4)
fmt.Println("r is", r)
wg.Done()
}()
fmt.Println("开始等待...")
wg.Wait()
fmt.Println("都完成了...")
}
func add(a int, b int) (c int) {
return a + b
}
//开始等待...
//r is 3
//r is 5
//r is 7
//都完成了...
//这个例子太简单, 都说并发编程是go 最牛叉的特性, 这里还不能充分体现出来;
//结合channel 等编程, 才是实战中最常用的情况;
13. select
一个select语句用来选择哪个case中的发送或接收操作可以被立即执行。它类似于switch语句,但是它的case涉及到channel有关的I/O操作
package main
import (
"fmt"
"time"
)
func main() {
// 本例中,我们从两个通道中选择
c1 := make(chan string)
c2 := make(chan string)
// 为了模拟并行协程的阻塞操作,我们让每个通道在一段时间后再写入一个值
go func() {
//每1秒发送
for {
time.Sleep(time.Second * 1)
c1 <- "one"
}
}()
go func() {
//每2秒发送
for {
time.Sleep(time.Second * 2)
c2 <- "two"
}
}()
// 我们使用select来等待这两个通道的值,然后输出
for i := 0; i < 10; i++ {
select {
case msg1 := <-c1:
fmt.Println("received from c1", msg1)
case msg2 := <-c2:
fmt.Println("received from c2", msg2)
}
}
}
14. chan
channel 通道, 可以理解为一个简单的消息队列;
一般结合内置函数 make 使用;
c1 := make(chan string)
c2 := make(chan string, 10)