1、 go基础

1、Go 语言最主要的特性

2、$GOPATH目录约定有三个子目录

3、$GOROOT GO安装目录,为了直接使用go命令,设置环境变量 $GOROOT/bin

4、程序入口

fun main() {
	//执行语句
}

⚠️ init 函数

main() init(),都没有参数和返回值

5、import

	import (
    . "fmt"
	)
import(
    _ "github.com/ziutek/mymysal/godrv"
)

6、在go中++和--等操作符只会用于语句而非表达式中,可能只可以做成后缀操作符而非前缀操作符。即go中不会出现 f(i++) 或 A[i]=b[++i] 这样的表达式

7、在go语言中只讲类型和值,而非类、对象或实例

8、变量声明

varname  type =

var   varname  type =

var  (
       varname  type
       varname  type
)

-函数体内部局部声明:varname :=

func m() {
   a = "O" //全局修改变量的值
   a := "p" //函数体内部的简短声明,为局部变量
   print(a)
}

9、数据类型

1)整型

2) float

3) bool

4)字符串 string "双引号书写",“ ` 反引号支持多行”

5)字符 单引号

10、常量

const name type = ' s'

隐式声明 const name = "adAD"
存储在常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数complex)和字符串型
Go 中不允许不同类型之间的混合使用,但是对于常量的类型限制非常少,因此允许常量之间的混合使用,

	var a int
	var b int32
	a = 15
	b = a + a	 // 编译错误
	b = b + 5    // 因为 5 是常量,所以可以通过编译

声明多个常量,未赋值则从上面获取,iota ,常量计数器,从0开始,可用作枚举

const (
	a = 10
	b
	c
)

11、条件控制

if  num%2 == 0  {

} else if  {

}

//特殊写法
if   varname,ok := mapdata[key]; ok {
}
switch  var1{
	case val1: 
		statement
	case val2:
		statement
	default:
		statement
}
//select 类似switch,随机执行一个分支
select {
    case <- c:
        fmt.Printf("Unblocked %v later.\n", time.Since(start))

    case <- ch1:
        fmt.Printf("ch1 case...")

    case <- ch2:
        fmt.Printf("ch1 case...")

    default:
        fmt.Printf("default go...")
    }

12、循环

for 循环:

for 初始语句int;条件语句;post语句变量增值变动 {
			statement
}
//post语句是每次循环的最后执行;
for i:= 0;i<=10;i++{
}

形式一、这三条语句可以省略,但是分号;不可省略
形式二、只有条件语句
 var i int
 for i <= 10 {
	}
形式三、相当于python中的while True:
for  {
   }
形式四:for key,value := range oldmap{
 			statement
	}

break continue goto 可以控制循环

labelname: statement
goto labelname

13、函数

func funcname(paramname type1,paramname type2) (output1 type1, ...) {
	statement
	return output1,...   //可返回多个值
}

不定数量的参数(可变长参数)
func funcname( arg ...int) (output1 type1,) {

}   //arg 本质是 int型的slice,相当于 [ ]int,若传入slice时,需展开([ ]int...)

变量声明的地方:

14、指针(一个变量的内存地址)

var name *int     //指针声明
var a int = 100
name = &a    //获取地址值
*name   //获取指针指向的值

15、GO语言内置容器

1)数组

var varname [ 数组长度 数据类型

var nums = [5]int{1,2,3,5,6}    
var nums = [...]int{1,2,3,5,6} 
//只能放统一类型的数据,数组一旦定义后,大小不能改变

2)切片

var  varname []type    
var slice []type = make([]type,len,capacity)

//也可以截取数组来初始化切片
arr := [5]int{1,2,35,5,6}
slice := arr[start:end]

append(slice,addnumber)函数,注意:

copy(var1,var2)

将var2 的内容拷贝到 var1, 完全复制过去,操作时互不影响,
通过切片、append 实现slice删除元素

3)map

切片,函数等引用类型数据不能做键值

声明
var  mapname  map[string]string  //该初始是一个 nil 空指针,无法存储值,除非声明的同时初始化数据
var  country = map[string]string{
	"china":"beijing",
}

name := make(map[key类型]value类型)   //提前申请了空间

//遍历
for  k,v := range map{

}

value,ok := map[key]    //获取value,  如果 ok is true,则存在,否则返回空字符串“”;
delete(map,key)   //删除一个键值对
//清空 map  可以创建一个空的map,将原值覆盖;

4)list

//声明
name  := list.New()  建议使用; 引用类型
var name list.List     值类型


//Element
func ( e  *Element)  Next()  *Element
func ( e  *Element)  Prev()  *Element

//List
func  New() *List    //List包创建list
func ( l  *List)  Init()  *List
func ( l  *List)  Len()  *List
func ( l  *List)  Front()  *Element    //获取首个元素
func ( l  *List)  Back()  *Element    //获取最后一个元素
func ( l  *List)  PushFront( v  interface{})  *Element    //头部添加一个元素
func ( l  *List)  PushFrontList( v  *LIst)  *List   
func ( l  *List)  InsertBefore( v insterface{},mark *Element) * Element
func ( l  *List) MoveToFront(mark *Element) //将一个元素移到头部
func ( l  *List) MoveBefore(v isnterface{}, mark *Element).
func ( l  *List) Remove(e *Element)  interface{}

16、面向对象

type

定义一个结构体
type Teaher struct {
	name string
	age int8
	sex byte
}

5种声明方式
1. var 声明
 
var  p Teacher
p.name = ''david"
p.age = 30
p.sex = 1

2. 简短声明
p := Teacher{}
p.name = ''david"
p.age = 30
p.sex = 1

3. 直接声明并赋值
p = Teacher{ name:‘’sdff“,age: 25,sex:1}

4.不写属性名,但是需按照顺序
p = Teacher{ "sdhn",30,0}

5.创建指针类型结构体  new( )
p := new( Teacher)
*p.name = "fjgns"
*p.age = 31
p.sex = 0   语法糖简写

匿名结构体和匿名字段

//没有名字的结构体:
	a := struct {字段的定义}{赋值}
//匿名字段,可以理解为字段名和字段类型一致
        type A struct{
		string
		int
	}
	b := A{"字符串", 20}
	b.string, b.int

type  A struct{
      
}

//匿名字段可以模拟继承关系
type B struct{
	A  //匿名字段的继承关系,一个类作为另一个类的子类,定义一个匿名字段struct.file, 继承属性和方法
}

// 聚合关系,一个类作为另一个类的属性,定义一个字段其类型是一个结构体,访问相关属性,struct.filestruct.file
type B struct{
	filedname  A
}

方法(包含接收者的函数)

方法可以同名,只要接受者不同就可以

func  (接受者变量  接受者类型)   方法名( 参数列表) (返回值列表){
			//方法体
}   

接口,无法直接实例化

1.定义接口
type  接口名字  interface {
	方法1(参数列表)返回值列表
	方法2(参数列表)返回值列表
}

2.定义结构体
type 结构体名 struct {
	//属性
}

3.实现接口的方法
func (变量名  结构体类型)  方法1(参数列表) 返回值

func main( ) {
	var  port  定义的接口类型
	port = new( 定义的实现该接口的结构体)
}

4、接口断言
nstance,ok := 接口对象 . (实际类型) //一般配合switch\case 使用

注意:接口类型对象,不能访问其实现类中的属性字段
	 定义方法时,修改属性字段,由于struct传参时,是值类型,所以需要传入指针。
	 定义一个接口变量,那么实际上可以赋值实现这个接口的任意对象(一般利用一个空接口)
如定义一个接口类型容器(数组或切片),实际上该容器中可以存储实现这个接口的任意对象
	   //要改变对象的值必须用指针
		func (b *User) SetName(name string) {
   		  	b.Name = name
		}

17、错误处理

创建error对象的几种方式
 1)  errors包下的New()函数返回error对象
	errors.New()  //创建一个新的错误

package errors
//返回一个新定义的错误结构体
func New( text string) error {
	return &errorString{ text}
}


2) fmt包下的Errorf()函数返回error对象,其本质还是调用 errors.New()
func  Errorf (formmat string,a ...interface{}) error {
return errors.New(Sprintf(format, a...))
}

3)自定义错误
  定义一个结构体,表示自定义的错误
  type errorString struct {
		s  string
	}

	func ( e *errorString)  Error() string {
		return e.s
	}

18.defer 延迟

defer 应用

下面这个函数检查作为其参数的函数执行时是否会  panic

func throwsPanic( f  func() )  b bool {
defer func( ) {
if x: = recover( );x != nil {
	b = true
	}()    //声明一个匿名函数并调用
	f( ) // 执行函数f,如果出现 panic  ,程序中止,执行延迟语句,恢复回来
	return
}

19、闭包 环境变量 + 函数,具有数据的行为,返回函数

func  getSequence()  func( )  int {
	i := 0
	return func() int {
		i += 1
		return i
	}
}

func main( ) {
nextNumber := getSequence( )
// 调用nextNumber 函数, i 变量自增 1 并返回
fmt.Println( nextNumber( ) )
fmt.Println( nextNumber( ) )

nextNumber1 := getSequence( )
// 新创建nextNumber1函数, i 变量从0开始,自增 1 并返回
fmt.Println( nextNumber1( ) )
fmt.Println( nextNumber1( ) )

输出结果
>>> 	1
>>>  2
>>> 	1
>>>  2

20、go的并发

21、通道channel

操作符 <- 用于指定通道方向,表示发送或接收,若未指定方向,则为双向通道

ch <- v  //把 v 发送到通道ch
v := <- ch  // 从ch 接收数据 并赋值给v
ch : = make( chan int )  声明一个带缓存通道,默认通道是不带缓冲区的,
- 带缓冲区的通道允许发送端的数据发送和接收端的数据获取处于异步状态,就是说发送端发送的数据可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。
- 不过由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了。
- 如果缓冲区已满,发送方阻塞;缓冲区无数据,接收方阻塞

package main

import "fmt"
func sum(s []int, c chan int) {
        sum := 0
        for _, v := range s {
                sum += v
        }
        c <- sum // 把 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)
}
Go 通过 range 关键字来实现遍历读取到的数据,类似于与数组或切片。格式如下:

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)
        // range 函数遍历每个从通道接收到的数据,因为 c 在发送完 10 个
        // 数据之后就关闭了通道,所以这里我们 range 函数在接收到 10 个数据
        // 之后就结束了。如果上面的 c 通道不关闭close(),那么 range 函数就不
        // 会结束,将一直处于阻塞状态。
        for i := range c {
                fmt.Println(i)
        }
}

1、 go基础

全文结束