当前位置:首页 > 科技  > 软件

Go语言的常用基础

来源: 责编: 时间:2024-01-02 09:30:53 129观看
导读一、核心特性Go语言有一些让人影响深刻的核心特性核心特性,比如:以消息传递模式的并发、独特的_符号、defer 、函数和方法、值传递等等,可以查看这篇文章《Go语言-让我印象深刻的13个特性》。首先要记住一些核心特性的用

一、核心特性

Go语言有一些让人影响深刻的核心特性核心特性,比如:以消息传递模式的并发、独特的_符号、defer 、函数和方法、值传递等等,可以查看这篇文章《Go语言-让我印象深刻的13个特性》。首先要记住一些核心特性的用法。9TY28资讯网——每日最新资讯28at.com

9TY28资讯网——每日最新资讯28at.com

1.Goroutine

  • 协程:独立的栈空间,共享堆空间,比线程更轻量。
  • 线程:一个线程上可以跑多个协程。
  • Go语言独有的协程,让程序员非常方便的使用并发编程,从而保留更多的心智去思考业务和创新。笔者认为这一点是Go语言最大的特性。

Goroutine就是这种协程特性的实现。Goroutine 是通过通信来共享内存,而不是共享内存来通信。通过共享内存来控制并发,会使编程变得更复杂,容易引入更多的问题。9TY28资讯网——每日最新资讯28at.com

Goroutine是由Go的运行时调度和管理。Go程序会智能地将 Goroutine 中的任务合理地分配给每个CPU,它在语言层面已经内置了调度和上下文切换的机制,不需要程序员去操作各种方法实现调度。9TY28资讯网——每日最新资讯28at.com

在Go语言中,当需要让某个任务并发执行时,只需要把这个任务包装成一个函数,开启一个Goroutine去执行就可以了。如下,只需要在调用函数时,在前面加上go关键字。9TY28资讯网——每日最新资讯28at.com

func hello_go() {  fmt.Println("hello go!!!")}func main() {    go hello_go()    fmt.Println("main done!!!")    time.Sleep(time.Second)}

2.接口

在Go语言中接口interface是一种类型。Go语言的接口比较松散,只要是实现了接口定义的方法,就是实现了这个接口,无需使用implement等关键字去声明。9TY28资讯网——每日最新资讯28at.com

定义接口:9TY28资讯网——每日最新资讯28at.com

// 定义接口type Sayer interface {  say()}// 定义结构体type dog struct {}type cat struct {}// 定义方法func (d dog) say() {  fmt.Println("狗叫")}func (c cat) say() {  fmt.Println("猫叫")}

空接口可以存储任意类型:9TY28资讯网——每日最新资讯28at.com

// 比如定义一个map类型的对象var obj = map[string]interface{}

使用类型断言判断空接口中的值:9TY28资讯网——每日最新资讯28at.com

// x:表示类型为interface{}的变量// T:表示断言x可能是的类型。x.(T)
func main() {  var x interface{}  x = 123  //v, ok := x.(int)  v, ok := x.(string)  if ok {    fmt.Println(v)  } else {    fmt.Println("类型断言失败")  }}

接口特性:9TY28资讯网——每日最新资讯28at.com

  • 接口类型变量能够存储所有实现了该接口的实例。 如下,Sayer类型的变量能够存储dog和cat类型的变量。
// 定义接口type Sayer interface {  say()}// 定义结构体type dog struct {}type cat struct {}// 定义方法func (d dog) say() {  fmt.Println("狗叫")}func (c cat) say() {  fmt.Println("猫叫")}func main(t *testing.T) {  var x Sayer // 声明一个接口类型的变量  c := cat{}  // 实例化cat  d := dog{}  // 实例化dog  x = c       // cat赋值给接口类型  x.say()     // 打印:猫叫  x = d       // dog赋值给接口类型  x.say()     // 打印:狗叫}
  • 一个类型可以同时实现多个接口,接口间彼此独立。
// 定义接口type Sayer interface {  say()}type Mover interface {  move()}// 定义结构体type dog struct {}// 定义方法func (d dog) say() {  fmt.Println("狗叫")}func (d dog) move() {  fmt.Println("狗移动")}func main(t *testing.T) {  var x Sayer  var y Mover  var d = dog{}  x = d  y = d  x.say()  y.move()}
  • 使用值接收者实现接口 和 使用指针接收者实现接口 有什么区别?值接受者实现时 可以用 指针类型赋值过去,但 指针接受者实现时 无法用 值类型赋值过去。
// 定义接口type Mover interface {  move()}type Sayer interface {  say()}// 定义结构体type dog struct {}// 定义方法func (d *dog) say() {  fmt.Println("狗叫")}func (d dog) move() {  fmt.Println("狗移动")}func TestProgram(t *testing.T) {  var x Sayer  var y Mover  //var d = dog{}  var d = &dog{}  x = d        // x不可以接收 dog类型,因为golang 不会 将值类型 转换 为指针类型  y = d     // y可以接受  *dog类型,因为golang 会 将指针类型 转换 为值类型  x.say()  y.move()}

3.下划线

_是特殊标识符,用来忽略结果。9TY28资讯网——每日最新资讯28at.com

buf := make([]byte, 1024)f, _ := os.Open("/Users/***/Desktop/text.txt")

4.Go语言中的指针

  • &:用于获取变量的地址,其实就是所谓的指针类型**(地址类型)
  • :用于获取指针所指向的值*

9TY28资讯网——每日最新资讯28at.com

func main() {  a := 10  fmt.Printf("type of a: %T/n", a)  b := &a // 取变量a的地址,将指针保存到b中  fmt.Printf("type of b: %T/n", b)  c := *b // 取出 指针b 所指向的值  fmt.Printf("type of c: %T/n", c)  fmt.Printf("value of c: %v/n", c)}

5.new和make的区别

  • 二者都是用来做内存分配的。
  • make只用于slice、map、channel的初始化,返回的还是这三个引用类型本身。这里的引用有别于指针,他是对 slice、map、channel 值的间接访问,并不是一个指向 slice、map、channel 的指针。
  • new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。指针是一个变量,存储了值的内存地址。

6.defer延迟调用

关键字 defer 用于注册延迟调用。这些调用直到 return 前才被执。可以用来做资源清理,常用来关闭资源。defer 是先进后出。9TY28资讯网——每日最新资讯28at.com

func main() {  arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}  for _, v := range arr {    defer fmt.Println("循环:", v)  }  fmt.Println("主流程跑完")  time.Sleep(time.Second * 3)  // 等待3秒后,执行defer,输出时先输出10,最后输出1,因为是先进后出}

二、常用类型和内置函数

1.常用类型

bool                                // 布尔int, int8, int16, int32, int64      // 整数uint, uint8, uint16, uint32, uint64 // 0 和正整数float32, float64                    //浮点数string                              // 字符串complex64, complex128               // 数学里的复数array     // 固定长度的数组struct    // 结构体string    // 字符串slice     // 序列数组map       // 映射chan      // 管道interface // 接口 或 任意类型func      // 函数

2.常用内置函数

append          // 追加元素到数组copy            // 用于复制和连接slice,返回复制的数目len             // 求长度,比如string、array、slice、map、channelcap             // capacity是容量的意思,用于返回某个类型的最大容量(只能用于切片和 map)delete          // 从map中删除key对应的valuepanic           // 抛出异常(panic和recover:用来做错误处理)recover         // 接受异常make            // 分配内存,返回Type本身(只能应用于slice, map, channel)new             // 分配内存,主要用来分配值类型,比如int、struct。返回指向Type的指针close           // 关闭channel

三、变量、常量

// 申明变量var name string// 申明常量const pi = 3.1415const e = 2.7182// 或const (        pi = 3.1415        e = 2.7182    )// 申明并且初始化n := 10

四、数据结构

1.数组

数组的长度固定:9TY28资讯网——每日最新资讯28at.com

var arr1 = [5]int{1, 2, 3, 4, 5}// 或arr2 := [...]struct {  name string  age  int8}{  {"yangling", 1},  {"baily", 2},}

2.切片

切片的长度不固定:9TY28资讯网——每日最新资讯28at.com

// 1.声明切片var s1 []ints2 := []int{}var s3 = make([]int, 0)// 向切片中添加元素s1 = append(s1, 2, 3, 4)// 从切片中按照索引获取切片s1[low:high]// 循环for index, element := range s1 {  fmt.Println("索引:", index, ",元素:", element)}

3.Map

scoreMap := make(map[string]int)scoreMap["张三"] = 90scoreMap["李四"] = 100userInfo := map[string]string{  "username": "baily",  "password": "111111",}// 如果key存在ok 为true,v为对应的值;// 如果key不存在ok 为false,v为值类型的零值v, ok := scoreMap["李四"]if ok {  fmt.Println(v)} else {  fmt.Println("查无此人")}// 循环for k, v := range scoreMap {  fmt.Println(k, v)}//将王五从map中删除delete(scoreMap, "王五")

4.结构体

不同的使用方式,可能返回指针,也可能返回值。9TY28资讯网——每日最新资讯28at.com

// 定义结构体type Student struct {  name string  age  int}func main() {  // 使用结构体  // 方式1,返回的是值  var stu1 Student  stu1.name = "baily"  stu1.age = 1  fmt.Println("baily1:", stu1)  // 方式2,返回的是值  var stu2 = Student{    name: "baily",    age:  1,  }  fmt.Println("baily2:", stu2)  // 方式3,返回的是指针  stu3 := &Student{    name: "baily",    age:  1,  }  fmt.Println("baily3指针:", stu3)  fmt.Println("baily3值:", *stu3)  // 方式4,返回的是指针  var stu4 = new(Student)  stu4.name = "baily"  stu4.age = 1  fmt.Println("baily4指针:", stu4)  fmt.Println("baily4值:", *stu4)}

五、流程控制

流程控制包括:if、switch、for、range、select、goto、continue、break。主要记下select,其他的跟别的语言类似。主要用于等待资源、阻塞等待等等。9TY28资讯网——每日最新资讯28at.com

select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。9TY28资讯网——每日最新资讯28at.com

func main() {  var c1 = make(chan int)  go func() {    time.Sleep(time.Second * 10)    c1 <- 1  }()  // 此处会一直等到10S到期,通道里有值才会继续往下走。  // 如果增加了 time.After(time.Second * 3) ,则最多3秒则结束  // 如果这2个case都不行,会走default,也可以不设置default  select {  case i, ok := <-c1:    if ok {      fmt.Println("取值", i)    }  case <-time.After(time.Second * 3):    fmt.Println("request time out")  default:    fmt.Println("无数据")  }}

六、函数和闭包

1.函数

// 正常函数func test(x int, y int, s string) (int, string) {    n := x + y              return n, fmt.Sprintf(s, n)}// 匿名函数func main() {    getSqrt := func(a float64) float64 {        return math.Sqrt(a)    }    fmt.Println(getSqrt(4))}

2.闭包

在Go语言中,闭包是一种函数值,它引用了其函数体外部的变量。闭包允许函数访问并处理其外部范围内的变量,即使函数已经返回了,这些外部变量也会被保留在闭包内。9TY28资讯网——每日最新资讯28at.com

所以说,一个闭包由两部分组成:函数体 和 与其相关的引用外部变量的环境。9TY28资讯网——每日最新资讯28at.com

当一个函数被定义在另一个函数内部时,并且引用了外部函数的变量,就会创建一个闭包。这个闭包函数可以随时访问和修改外部函数中的变量,即使外部函数已经执行完毕。9TY28资讯网——每日最新资讯28at.com

func main() {  // 外部函数定义并返回内部函数  add := adder()    // 通过闭包调用内部函数,increment是闭包函数  fmt.Println(add(1)) // 输出:1  fmt.Println(add(2)) // 输出:3  fmt.Println(add(3)) // 输出:6}// 外部函数,返回一个闭包函数func adder() func(int) int {  sum := 0 // 外部函数中的变量  // 闭包函数  return func(x int) int {    sum += x // 闭包函数使用了外部函数中的变量    return sum  }}

七、异常

1.内置接口error

type error interface { //只要实现了Error()函数,返回值为string的都实现了err接口   Error()    string}

2.异常处理

使用 panic 抛出错误,然后在defer中通过recover捕获异常。9TY28资讯网——每日最新资讯28at.com

func main() {    testPanic()}func testPanic() {  defer func() {    if err := recover(); err != nil {      fmt.Println(err.(string))    }  }()  panic("抛出异常")}

3.返回异常

// 隐式地返回2个值func getCircleArea(radius float32) (area float32, err error) {  if radius < 0 {    // 构建个异常对象    err = errors.New("半径不能为负")    return  }  area = 3.14 * radius * radius  return}func main() {  area, err := getCircleArea(-5)  if err != nil {    fmt.Println(err)  } else {    fmt.Println(area)  }}

八、面向对象和方法

11.面向对象

可以使用匿名字段:9TY28资讯网——每日最新资讯28at.com

type Person struct {  name string  age  int}type Student struct {  Person  id   int  addr string}func main() {    s1 := Student{      Person{"baily", 20},      1,      "南京市雨花台区南京南站",    }    fmt.Println(s1)}

如果对象内部嵌套的对象有同名字段的情况,只取对象自己的字段:9TY28资讯网——每日最新资讯28at.com

type Person struct {  name string  age  int}type Student struct {  Person  id   int  addr string  name string}func main() {  var s Student  s.name = "baily"  s.Person.name = "baily-parent"  fmt.Println(s) // 打印出 baily   }

2.方法

一个方法就是一个包含了接受者的函数,接受者可以是 类型或者结构体 的值或者指针。9TY28资讯网——每日最新资讯28at.com

type Test struct{}// 多参数、多返回值func (t Test) method1(x, y int) (z int, err error) {  return}// 多参数、多返回值func (t *Test) method2(x, y int) (z int, err error) {  return}

3.指针接受者 和 值接受者的区别

当方法作用于值接收者时,Go语言会在代码运行时将接收者的值复制一份。在值接收者的方法中可以获取接收者的成员值,但修改操作只是针对复制出来的副本,无法修改接收者本身。9TY28资讯网——每日最新资讯28at.com

而指针接受者,在修改成员时,会修改接受者本身。9TY28资讯网——每日最新资讯28at.com

// SetAge 设置p的年龄// 使用指针接收者func (p *Person) SetAge(newAge int) {  p.age = newAge}// SetAge2 设置p的年龄// 使用值接收者func (p Person) SetAge2(newAge int) {  p.age = newAge}func main() {  p := new(Person)  p.age = 11  p.SetAge(22)   // 对象p的age会被改变  fmt.Println(p.age)  p.SetAge2(33)  // 对象p的age不会被改变  fmt.Println(p.age)}

什么时候应该使用指针接受者?9TY28资讯网——每日最新资讯28at.com

  • 需要修改接收者中的值
  • 接收者是拷贝代价比较大的大对象
  • 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。

九、网络编程

TCP编程:9TY28资讯网——每日最新资讯28at.com

// 处理函数func process(conn net.Conn) {  defer conn.Close() // 关闭连接  for {    reader := bufio.NewReader(conn)    var buf [128]byte    n, err := reader.Read(buf[:]) // 读取数据    if err != nil {      fmt.Println("读取客户端数据失败:", err)      break    }    recvStr := string(buf[:n])    fmt.Println("收到client端发来的数据:", recvStr)    conn.Write([]byte("回复客户端:" + recvStr)) // 发送数据  }}func main() {  listen, err := net.Listen("tcp", "127.0.0.1:9587")  if err != nil {    fmt.Println("启动监听异常:", err)    return  }  for {    conn, err := listen.Accept() // 建立连接    if err != nil {      fmt.Println("没有连接:", err)      continue    }    go process(conn) // 启动一个goroutine处理连接  }}

十、并发编程

1.使用sync.WaitGroup

var wg sync.WaitGroupfunc hello_wg(i int) {  defer wg.Done() // goroutine结束就登记-1  fmt.Println("hello_wg!", i)}func main() {  for i := 0; i < 10; i++ {    wg.Add(1) // 启动一个goroutine就登记+1    go hello_wg(i)    time.Sleep(time.Second)  }  wg.Wait() // 等待所有登记的goroutine都结束}

2.使用channel解决并发

Go语言的并发模型是CSP(Communicating Sequential Processes),通过通信共享内存,而不是通过共享内存而实现通信。9TY28资讯网——每日最新资讯28at.com

9TY28资讯网——每日最新资讯28at.com

func recv(c chan int) {  ret := <-c  fmt.Println("接收成功", ret)}func main() {  c := make(chan int)  go recv(c) // 启用goroutine从通道接收值  c <- 10  fmt.Println("发送成功")   }

3.select

func main() {  var c1 = make(chan int)  go func() {    time.Sleep(time.Second * 10)    c1 <- 1  }()  // 此处会一直等到10S到期,通道里有值才会继续往下走。  // 如果增加了 time.After(time.Second * 3) ,则最多3秒则结束  // 如果这2个case都不行,会走default,也可以不设置default  select {  case i, ok := <-c1:    if ok {      fmt.Println("取值", i)    }  case <-time.After(time.Second * 3):    fmt.Println("request time out")  default:    fmt.Println("无数据")  }}

4.互斥锁

多个go协程操作同一个资源时,会发生并发问题,需要加锁解决。有互斥锁,还有读写锁。9TY28资讯网——每日最新资讯28at.com

func add() {  for i := 0; i < 5000; i++ {    // 如果不加锁,此处会有并发问题    lock.Lock() // 加锁    x = x + 1    lock.Unlock() // 解锁  }  wg.Done()}func main() {  wg.Add(2)  go add()  go add()  wg.Wait()  fmt.Println(x)   }

十一、单元测试

文件以_test.go结尾,方法以Test开头,方法入参t *testing.T。9TY28资讯网——每日最新资讯28at.com

func TestProgram(t *testing.T) {  split := strings.Split("a,b,c", ",")  defer func() {    if err := recover(); err != nil {      fmt.Println("异常:", err)    }  }()  findElement(split, "a")}// 查找元素func findElement(split []string, target string) {  flag := false  for _, e := range split {    if e == target {      flag = true      break    }  }  if flag {    fmt.Println("已经找到")  } else {    panic("没找到")  }}

十二、常用命令

  • go env:用于打印Go语言的环境信息。
  • go build:用于编译Go程序。例如,go build filename.go 会将 filename.go 编译成可执行文件。
  • go run:用于直接运行Go程序。例如,go run filename.go 会编译并运行 filename.go 文件中的程序。
  • go test:用于运行测试文件或者测试包。例如,go test 会运行当前目录下所有的测试文件。
  • go get:用于下载并安装包。例如,go get github.com/example/package 会下载 github.com/example/package 包并将其安装在 $GOPATH/src 下。
  • go mod:用于管理依赖和模块。例如,go mod init 用于初始化一个新的模块,并生成 go.mod 文件。
  • go vet:用于静态检查Go代码中的错误。例如,go vet filename.go 会检查 filename.go 文件中的错误。
  • go install 命令用于编译并安装Go程序,它会编译指定的包或源文件,并将生成的可执行文件安装到 $GOPATH/bin 目录下。

本文链接:http://www.28at.com/showinfo-26-55136-0.htmlGo语言的常用基础

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Typedef在C语言和C++中有什么区别?

下一篇: 通过Uri加载raw目录下的文件

标签:
  • 热门焦点
  • 5月iOS设备好评榜:iPhone 14仅排第43?

    5月iOS设备好评榜:iPhone 14仅排第43?

    来到新的一月,安兔兔的各个榜单又重新汇总了数据,像安卓阵营的榜单都有着比较大的变动,不过iOS由于设备的更新换代并没有那么快,所以相对来说变化并不大,特别是iOS好评榜,老款设
  • 十个可以手动编写的 JavaScript 数组 API

    十个可以手动编写的 JavaScript 数组 API

    JavaScript 中有很多API,使用得当,会很方便,省力不少。 你知道它的原理吗? 今天这篇文章,我们将对它们进行一次小总结。现在开始吧。1.forEach()forEach()用于遍历数组接收一参
  • K8S | Service服务发现

    K8S | Service服务发现

    一、背景在微服务架构中,这里以开发环境「Dev」为基础来描述,在K8S集群中通常会开放:路由网关、注册中心、配置中心等相关服务,可以被集群外部访问;图片对于测试「Tes」环境或者
  • 一篇聊聊Go错误封装机制

    一篇聊聊Go错误封装机制

    %w 是用于错误包装(Error Wrapping)的格式化动词。它是用于 fmt.Errorf 和 fmt.Sprintf 函数中的一个特殊格式化动词,用于将一个错误(或其他可打印的值)包装在一个新的错误中。使
  • Java NIO内存映射文件:提高文件读写效率的优秀实践!

    Java NIO内存映射文件:提高文件读写效率的优秀实践!

    Java的NIO库提供了内存映射文件的支持,它可以将文件映射到内存中,从而可以更快地读取和写入文件数据。本文将对Java内存映射文件进行详细的介绍和演示。内存映射文件概述内存
  • 冯提莫签约抖音公会 前“斗鱼一姐”消失在直播间

    冯提莫签约抖音公会 前“斗鱼一姐”消失在直播间

    来源:直播观察提起&ldquo;冯提莫&rdquo;这个名字,很多网友或许听过,但应该不记得她是哪位主播了。其实,作为曾经的&ldquo;斗鱼一姐&rdquo;,冯提莫在游戏直播的年代影响力不输于现
  • 认真聊聊东方甄选:如何告别低垂的果实

    认真聊聊东方甄选:如何告别低垂的果实

    来源:山核桃作者:财经无忌爆火一年后,俞敏洪和他的东方甄选依旧是颇受外界关心的&ldquo;网红&rdquo;。7月5日至9日,为期5天的东方甄选&ldquo;甘肃行&rdquo;首次在自有App内直播,
  • 与兆芯合作  联想推出全新旗舰版笔记本电脑开天N7系列

    与兆芯合作 联想推出全新旗舰版笔记本电脑开天N7系列

    联想与兆芯合作推出全新联想旗舰版笔记本电脑开天 N7系列。这个系列采用兆芯KX-6640MA处理器平台,KX-6640MA 处理器是采用了陆家嘴架构,16nm 工艺,4 核 4 线
  • 荣耀Magic4 至臻版 首创智慧隐私通话 强劲影音系统

    荣耀Magic4 至臻版 首创智慧隐私通话 强劲影音系统

    2022年第一季度临近尾声,在该季度内,许多品牌陆续发布自己的最新产品,让大家从全新的角度来了解当今的手机技术。手机是电子设备中,更新迭代十分迅速的一款产品,基
Top