Go基础语法笔记(来源 A tour of Go)

简单例子

package main //当前所在的文件名
import (     //引进包
	"fmt"
	"time"
)
//声明函数 函数名字 传入变量以及类型 结果的类型(有几个就写几个)
func add(x, y int) (int) {
	return x + y
} 

func main(){
	fmt.Println("Welcom to Go!",time.Now())
	fmt.Println(add(42,13))
}

包,变量,函数

  • 包:“fmt”,“time”
  • 变量:
  • 声明方式:
var x float32 =42 
x := float32(42)
  • 常见数据型:
    • bool,
    • string
    • int int8 int16 int32 int64
    • uint uint8 uint16 uint32 uint64 uintptr
    • float32/float64
    • complex64/complex128
    • 函数
    //函数写法1:声明 传入变量 函数名字 结果类型
    func (v Vertex) Abs() float64 {
    	return math.Sqrt(v.X*v.X + v.Y*v.Y)
    }
    
    //函数写法2:声明 函数名字 传入变量 结果(有几个就写几个类型)
    func add(x, y int) (int) {
       return x + y
    }
    // 函数写法3(内部方法):类名 函数名字 传入变量 结果类型  
    //内部方法和非内部方法区别:非内部方法默认导出,内部方法不导出
    //调用区别:非内部方法导出后可直接调用,内部方法导出后调用只能用 srv.add();
    func(srv Service) add(x, y int) (int) {
    	return x + y
    }
    

流程控制语句

  • for
//go的for语句没有括号
for i := 0; i < 10; i++ {
sum += i
}
//类似于其他语言的while写法
for sum < 1000 {
sum += sum
}
//无限循环
for {}
- if else
- 
//简单的判断
if x<0 {}
//可在里面正常生成一个
if v := math.Pow(x, n); v < lim {
return v
}
  • switch
switch i {
case 0:xxx,
case f()
}
  • defer
//defer定义的函数会立即求值,但要到外层结束后才会被调用
//其实质是压入一个栈
defer fmt.Println("world")

更多类型:指针,struct,数组,slice和映射

  • 指针,指针的零值为nil
//定义p的值
var p *int
//&操作符生成一个指向其操作数的指针
i := 42
p = &i
//*操作符表示指针指向的底层值
fmt.Println(*p) //通过指针p读取i
*p = 21         //通过指针p设置成i

package main

import "fmt"

func main() {
i, j := 42, 2701

p := &i         // 指向 i
fmt.Println(*p) // 通过指针读取 i 的值
*p = 21         // 通过指针设置 i 的值
fmt.Println(i)  // 查看 i 的值

p = &j         // 指向 j
*p = *p / 37   // 通过指针对 j 进行除法运算
fmt.Println(j) // 查看 j 的值
}
  • struct
//define the struct
type Vertex struct {
X int
Y int
}

//usage
v := Vertex{1, 2}
//结构体文法,通过直接列出字段的值来新分配一个结构体
//使用Name:语法可以仅列出部分字段
//特殊前缀&返回一个指向结构体的指针
var (
v1 = Vertex{1, 2}  // 创建一个 Vertex 类型的结构体
v2 = Vertex{X: 1}  // Y:0 被隐式地赋予
v3 = Vertex{}      // X:0 Y:0
p  = &Vertex{1, 2} // 创建一个 *Vertex 类型的结构体(指针)
)
func main() {
fmt.Println(v1, p, v2, v3)
}
  • slice,make
  • 数组和切片的区别:数组一般是定长的,数组切片可以构建成slice
  • slice切片
//define array
var a [10]int
var a [10]int={2,3,5,7,11,13} //a :=[10]int{2,3,5,7,11,13}
//slice the array
a[low:high]
//slice length and capacity
// 截取切片使其长度为 0
s = s[:0]
printSlice(s)

// 拓展其长度
s = s[:4]
printSlice(s)

// 舍弃前两个值
s = s[2:]
printSlice(s)
  • make切片
//切片的cap是总容量,len是里面存在的具体个数
a := make([]int, 5)  // len(a)=5
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:]      // len(b)=4, cap(b)=4
  • 切片定义任何类型
// 创建一个井字板(经典游戏)
board := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}

// 两个玩家轮流打上 X 和 O
board[0][0] = "X"
board[2][2] = "O"
board[1][2] = "X"
board[1][0] = "O"
board[0][2] = "X"
  • 切片扩展
// 添加一个空切片
s = append(s, 0)
printSlice(s)

// 这个切片会按需增长
s = append(s, 1)
printSlice(s)

// 可以一次性添加多个元素
s = append(s, 2, 3, 4)
printSlice(s)
  • range
for i, _ := range pow{}
for _, value := range pow{}
for i := range pow{}
  • 映射 有点类似于js的json
//define the map
var m = map[string]Vertex{
	"Bell Labs": {40.68433, -74.39967},
	"Google":    {37.42202, -122.08408},
}
//插入或者修改
m[key] = elem
//获取元素
elem = m[key]
//删除元素
delete(m,key)
//通过双赋值检查某个键是否存在
value,ok=m[key]

方法

  • golang的方法可以作为值进行传递
  • 方法只是个带接收者参数的函数
//写法1
func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
//写法2
func Abs(v Vertex) float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
  • 和C语言类似的指针调用方法
    *p定义为指针函数,*p指向的地址才是实际的地址,使用&p传入形参
  • 指针为接受者的方法调用时,接收者即可以为值也可以为指针
var v Vertex
v.Scale(5)  // OK
Scale(5) //错误
p := &v
p.Scale(10) // OK
Scale(p)//Ok
  • 同样发生在传入赋值时
var v Vertex
fmt.Println(v.Abs()) // OK
fmt.Println(Abs(&v)) // 编译错误!
p := &v
fmt.Println(p.Abs()) // OK 这种状态下被自动解释为(*p).Abs()
  • 选择指针作为接收者的规律
    • 方法能够修改其接收者指向的值
    • 这样可以避免在每次调用方法时复制该值。若值的类型为大型结构体时,这样做会更加高效。

接口:一组方法定义签名定义的组合

  • 定义和使用:

    //例子,interface里面的方法
    type I interface {
    	M()
    }
    
  • 隐式实现

    package main
    
    import "fmt"
    //相当于函数里面的方法
    type I interface {
    	M()
    }
    //相当于类
    type T struct {
    	S string
    }
    
    // 此方法表示类型 T 实现了接口 I,但我们无需显式声明此事。
    func (t T) M() {
    	fmt.Println(t.S)
    }
    
    func main() {
    	var i I = T{"hello"}
    	i.M()
    }
    
  • 接口值:接口可作为值返回,使用标准符号 %T

  • nil值:未定义的接口值默认为nil,但不从逻辑上排除会报错

  • 空接口

    var i interface{}
    
  • 类型断言和类型选择

    //类型断言
    t,ok :=i,(Type)
    //example
    t,ok := i.(int)
    //类型选择
    switch v := i.(type) {
    case T:
        // v 的类型为 T
    case S:
        // v 的类型为 S
    default:
        // 没有匹配,v 与 i 的类型相同
    }
    
  • Stringer:fmt包中函数,可以重写fmt.Println()函数

    //interface
    type Stringer interface {
        String() string
    }
    //usage
    type Person struct {
        Name string
    	Age  int
    }
    func (p Person) String() string {
    	return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
    }
    
    func main() {
    	a := Person{"Arthur Dent", 42}
    	z := Person{"Zaphod Beeblebrox", 9001}
    	fmt.Println(a, z)
    }
    
  • 错误:与Stringer相似可以处理相应的值

    func (e *MyError) Error() string {
    	return fmt.Sprintf("at %v, %s",
    		e.When, e.What)
    }
    
  • Reader

    //使用例子
    func main() {
    	r := strings.NewReader("Hello, Reader!")
    
        //切片创造空间
    	b := make([]byte, 8)
    	for {
    		n, err := r.Read(b)
    		fmt.Printf("n = %v err = %v b = %v\n", n, err, b)
    		fmt.Printf("b[:n] = %q\n", b[:n])
    		if err == io.EOF {
    			break
    		}
    	}
    }
    
  • 图像

    //底层定义
    type Image interface {
        ColorModel() color.Model
        Bounds() Rectangle
        At(x, y int) color.Color
    }
    //使用例子
    func main() {
    	m := image.NewRGBA(image.Rect(0, 0, 100, 100))
    	fmt.Println(m.Bounds())
    	fmt.Println(m.At(0, 0).RGBA())
    }
    
    
    

并发

  • goroutine go程:Go 运行时管理的轻量级线程

    //command
    go f(x,y,z)
    
  • channel 信道:带有类型的管道,类似于携程

    //创建,信道在使用前必须创建
    ch := make(chan int);//默认只有一个数据
    //使用方法
    ch <- v    // 将 v 发送至信道 ch。
    v := <-ch  // 从 ch 接收值并赋予 v。
    
    //例子
    package main
    
    import "fmt"
    
    func sum(s []int, c chan int) {
    	sum := 0
    	for _, v := range s {
    		sum += v
    	}
    	c <- sum // 将和送入 c
    }
    
    func main() {
    	s := []int{7, 2, 8, -9, 4, 0}
    
    	c := make(chan int)
    	go sum(s[:len(s)/2], c)
    	go sum(s[len(s)/2:], c)
    	x, y := <-c, <-c // 从 c 中接收
    
    	fmt.Println(x, y, x+y)
    }
    
  • 带缓冲的channel:

    //初始化带缓存的信道
    ch := make(chan int, 100)
    
    //当信道填满后会阻塞
    package main
    
    import "fmt"
    
    func main() {
    	ch := make(chan int, 2)
    	ch <- 1
    	ch <- 2
    	fmt.Println(<-ch)
    	fmt.Println(<-ch)
    }
    
  • range和close

    • 发送者关闭close,只能由发送者关闭。如 close©.

    • 接收者通过表达式检测信道是否关闭。如 v,ok := <-ch.

    • 信道与文件不同,只有告诉发送者不再接受时才能不关闭。

      package main
      
      import (
      	"fmt"
      )
      
      func fibonacci(n int, c chan int) {
      	x, y := 0, 1
      	for i := 0; i < n; i++ {
      		c <- x
      		x, y = y, x+y
      	}
      	close(c)
      }
      
      func main() {
      	c := make(chan int, 10)
      	go fibonacci(cap(c), c)
      	for i := range c {
      		fmt.Println(i)
      	}
      }
      
  • select 语句:

    • 使得go等待多个通信操作。多个分支都准备好时随机选择一个执行;

      package main
      
      import "fmt"
      
      func fibonacci(c, quit chan int) {
      	x, y := 0, 1
      	for {
      		select {
      		case c <- x:
      			x, y = y, x+y
      		case <-quit:
      			fmt.Println("quit")
      			return
      		}
      	}
      }
      
      func main() {
      	c := make(chan int)
      	quit := make(chan int)
      	go func() {
      		for i := 0; i < 10; i++ {
      			fmt.Println(<-c)
      		}
      		quit <- 0
      	}()
      	fibonacci(c, quit)
      }
      
    • 当其他分支都没准备好时,default分支就会执行

    //model
    select {
    case i := <-c:
        // 使用 i
    default:
        // 从 c 中接收会阻塞时执行
    }
    
    //example
    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	tick := time.Tick(100 * time.Millisecond)
    	boom := time.After(500 * time.Millisecond)
    	for {
    		select {
    		case <-tick:
    			fmt.Println("tick.")
    		case <-boom:
    			fmt.Println("BOOM!")
    			return
    		default:
    			fmt.Println("    .")
    			time.Sleep(50 * time.Millisecond)
    		}
    	}
    }
    
    
  • asycn.Mutex互斥锁:

    • 比如:想保证每次只有一个Go程能够访问一个共享的变量

    • Lock

    • Unlock

      package main
      
      import (
      	"fmt"
      	"sync"
      	"time"
      )
      
      // SafeCounter 的并发使用是安全的。
      type SafeCounter struct {
      	v   map[string]int
      	mux sync.Mutex
      }
      
      // Inc 增加给定 key 的计数器的值。
      func (c *SafeCounter) Inc(key string) {
      	c.mux.Lock()
      	// Lock 之后同一时刻只有一个 goroutine 能访问 c.v
      	c.v[key]++
      	c.mux.Unlock()
      }
      
      // Value 返回给定 key 的计数器的当前值。
      func (c *SafeCounter) Value(key string) int {
      	c.mux.Lock()
      	// Lock 之后同一时刻只有一个 goroutine 能访问 c.v
      	defer c.mux.Unlock()
      	return c.v[key]
      }
      
      func main() {
      	c := SafeCounter{v: make(map[string]int)}
      	for i := 0; i < 1000; i++ {
      		go c.Inc("somekey")
      	}
      
      	time.Sleep(time.Second)
      	fmt.Println(c.Value("somekey"))
      }
      
  • Reference:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值