Go语言入门

go 专栏收录该内容
2 篇文章 0 订阅

安装Go环境

安装包下载地址:https://golang.org/dl/,打不开可以在https://studygolang.com/dl下载。
在这里插入图片描述
下载安装完成后可打开Win+R进入cmd查看是否安装成功,输入go version 成功显示版本号则安装成功
在这里插入图片描述

安装集成开发环境

LiteIDE下载地址:http://liteide.org/cn/
可以使用Go的集成开发环境LiteIDE,或是IntelliJ Idea安装Go插件。
插件安装路径:File->Settings
在这里插入图片描述

语法基础

包的声明

每个go文件的第一行声明该文件属于哪个包,package 包名 定义该文件的包名,main包表示独立可运行的go程序,每个go应用程序都包含一个叫main的包。

package main

包的导入

使用import关键字 + 包名导入依赖的包,包名使用双引号。

import "fmt"
import "math"

也可以使用圆括号分组形式导入包

import (
	"fmt"
 	"math"
)

导出名

在go中,只能使用模块中已导出的函数,已导出的函数都以大写字母开头。小写字母开头的方法只能在包内使用。

package main
import ("fmt"
	"math"
)
func main() {
	fmt.Printf("%g", math.Sqrt(2))
}

在这里插入图片描述

package main
import ("fmt"
	"math"
)
func main() {
	fmt.Printf("%g", math.sqrt(2))
}

在这里插入图片描述

函数

函数定义

go中的函数使用func关键字定义,注意参数类型在参数名之后,格式如下

func 函数名(参数名1 参数类型, 参数名2 参数类型) 返回值 {

}
package main
import (
	"fmt"
)
func main() {
	fmt.Printf("3 + 5 = %d", add(3, 5))
}
func add(a int, b int) int {
	return a + b
}

参数列表简化

当两个或以上参数类型相同时,参数类型可只保留最后一个,如上函数add可简化为

func add(a, b int) int {
	return a + b
}

多返回值

go中的函数可返回任意数量的返回值

package main
import (
	"fmt"
)
func main() {
	a, b := add(3, 5)
	fmt.Printf("3 + 5 = %d, 3 - 5 = %d", a, b)
}
func add(a, b int) (int, int) {
	return a + b, a - b
}

返回值的命名

可以直接命名返回值,没有参数的return语句返回已命名的返回值

func add(a, b int) (sum, difference int) {
	sum = a + b
	difference = a - b
	return
}

变量

变量使用var关键字定义,作用域可以是包或函数。

var flag bool
func main() {
	var i int
	flag = true
	i = 5
	fmt.Println(i, flag)
}

变量的初始化

变量可以在声明时初始化,如果变量在声明时初始化值可省略类型,变量可以从值中获取类型。

var flag = true
func main() {
	var i = 5
	fmt.Println(i, flag)
}

短赋值语句

在函数里:=可以取代类型明确的变量赋值中的var声明,但在函数外不可以使用

func main() {
	i := 5
	fmt.Println(i, flag)
}

基本数据类型

go中的基本数据类型同样可分为整型、浮点型、布尔型三大类

整型

整型的数据类型包含int8、int16、int32、int64、uint8、uint16、uint32、uint64,其中int开头的为有符号整型,unit开头的位无符号整型

浮点型

浮点型的数据类型包含float32、float64、complex64、complex128、uint8、uint16、uint32、uint64,其中int开头的为有符号整型,unit开头的位无符号整型。
float用于表示浮点数据,complex用于表是复数类型

布尔型

布尔型的值只可以是常量 true 或者 false

其他数字类型

其他数字类型包括byte、rune。
byte 等同于int8,常用来处理ascii字符
rune 等同于int32,常用来处理unicode或utf-8字符

// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.

//int32的别名,几乎在所有方面等同于int32
//它用来区分字符值和整数值

type rune = int32

零值

没有赋值的变量会被设置为零值
数字型:0
布尔型:false
字符串:""

package main
import (
	"fmt"
)
var (
	flag bool
	MaxInt uint64
	str string
)
func main() {
	fmt.Printf("Type: %T Value: %v\n", flag, flag)
	fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt)
	fmt.Printf("Type: %T Value: %v\n", str, str)
}

在这里插入图片描述

分支结构

go语言中的循环结构只有for一种

for

对比其他语言,go中的for的小括号可以省略

	sum := 0
	for i:= 1; i < 100; i ++ {
		sum += i
	}
	fmt.Printf("sum = %v", sum)

除了条件表达式外,初始化语句和后置语句是可选的

	sum := 1
	for sum < 10 {
		sum += sum
	}
	fmt.Printf("sum = %v", sum)

无限循环语句可视作没有条件表达式的for语句

	for {

	}

if

if语句和for语句类似,小括号可以省略,大括号不行

	flag := true
	if flag {
		fmt.Printf("true")
	} else {
		fmt.Printf("false")
	}

if 可以在条件表达式判定之前先做一些初始化的语句,该语句的作用域仅在if语句内有效

import (
	"fmt"
	"math"
)
func pow(x, n, lim float64) float64 {
	if v := math.Pow(x, n); v < lim {
		return v
	}
	return lim
}
func main() {
	fmt.Println(
		pow(3, 2, 10),
		pow(3, 3, 20),
	)
}

在这里插入图片描述

switch

go中的switch 的 case 语句从上到下顺次执行,直到匹配成功时停止,不会发生case穿透,只会执行第一个满足条件的case而不会执行后面的case

import (
	"fmt"
	"runtime"
)
func main() {
	fmt.Print("Go runs on ")
	switch os := runtime.GOOS; os {
	case "darwin":
		fmt.Println("OS X.")
	case "linux":
		fmt.Println("Linux.")
	case "windows":
		fmt.Println("windows")
	default:
		fmt.Printf("NULL")
	}
}

在这里插入图片描述

defer

defer修饰的语句会被推到调用栈里,待外层函数返回后执行,如果有多条语句用defer修饰,遵循后进先出的顺序

	fmt.Println("counting")
	for i := 0; i < 10; i++ {
		defer fmt.Println(i)
	}
	fmt.Println("done")

在这里插入图片描述
defer修饰的语句的参数是值传递,也就是在定义时就确定了值的

import "fmt"
func calc(index string, a, b int) int {
	ret := a + b
	fmt.Println(index, a, b, ret)
	return ret
}
func main() {
	x := 1
	y := 2
	defer calc("A", x, calc("B", x, y))
	x = 3
	defer calc("C", x, calc("D", x, y))
	y = 4
}

上述代码在执行过程中等价于

func main() {
	x := 1
	y := 2
	tempB := calc("B", x, y)
	defer calc("A", x, tempB)
	x = 3
	tempD := calc("D", x, y)
	defer calc("C", x, tempD)
	y = 4
}

在这里插入图片描述

指针

go中有指针,但不允许进行指针计算,* 类型声明这种类型的指针,零值为<nil>。
使用&操作符生成指向指定操作数的指针。

func main() {
	i := 1
	var p *int
	fmt.Println(p)
	p = &i//定义指向变量i的指针p
	fmt.Println(p)//变量i在内存中的存放地址
	fmt.Println(*p)
	*p = *p + 1
	fmt.Println(*p)
}

在这里插入图片描述

结构体

结构体(struct)就是一组字段,使用.号访问结构体中的字段

type Coordinate struct {
	X int
	Y int
}
func main() {
	v := Coordinate{1, 2}
	fmt.Println(v.X)
}

可使用结构体指针访问数据,也可以隐式间接引用

type Coordinate struct {
	X int
	Y int
}
func main() {
	var p *Coordinate
	p = &Coordinate{1, 2}
	fmt.Println((*p).X)//通过结构体指针访问
	fmt.Println(p.X)//隐式间接访问
}

可使用列出字段值的方法来分配结构体,未被分配值的字段为该类型的零值

type Coordinate struct {
	X int
	Y int
}
func main() {
	var p *Coordinate
	p = &Coordinate{X:1}
	fmt.Println((*p).X)
	fmt.Println(p.Y)
}

数组

go中使用 []类型 来声明数组

func main() {
	a := [5]int{1,2,3,4,5}
	fmt.Println(a)
}

切片

数组的大小都是固定的。而切片则为数组元素提供动态大小的、灵活的视角。
切片通过两个下标来界定,即一个上界和一个下界,二者以冒号分隔:
包含下界不包含上界

func main() {
	a := [5]int{1,2,3,4,5}
	var p = a[0:4]
	fmt.Println(p)
}

a[0:4]表示a数组中下标0到3的元素,切片并没有真正意义上存储数据,而只是描述数组中的一段数据,修改切片会修改数组中的对应元素。

func main() {
	a := [5]int{1,2,3,4,5}
	var p = a[0:3]
	var q = a[1:4]
	fmt.Println(p)
	fmt.Println(q)
	p[2] = 9
	fmt.Println(p)
	fmt.Println(q)
}

在这里插入图片描述
切片可以省略上下界,下界的默认值的0,上界的默认值为数组的长度
对于数组a [10]int,下面的切片是等价的

a[0:10]
a[:10]
a[0:]
a[:]

切片的长度指存放的元素个数,容量指从切片第一个元素开始到底层数组最后一个元素的个数。

func main() {
	s := []int{1, 3, 5, 7, 9, 11}
	printSlice(s)
	// 截取切片使其长度为 0
	s = s[:0]
	printSlice(s)
	// 拓展长度
	s = s[:4]
	printSlice(s)
	// 舍弃前两个值
	s = s[2:]
	printSlice(s)
	// 拓展长度
	s = s[:4]
	printSlice(s)
}
func printSlice(s []int) {
	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

切片的零值为nil且没有底层数组

func main() {
	var s []int
	fmt.Println(s, len(s), cap(s))
	if s == nil {
		fmt.Println("nil!")
	}
}

切片可以用内建函数make创建,双参数时第二个参数是长度和容量,三参数时第二个是长度,第三个是容量

func main() {
	a := make([]int, 5)
	fmt.Println(len(a), cap(a))
	s := make([]int, 0, 5)
	fmt.Println(len(s), cap(s))
}

在这里插入图片描述
可以通过append向切片追加元素,如果底层数组的容量不够,将创建新的数组,将切片指向新的数组。

func main() {
	var language = []string{"Java", "C", "Python"}
	fmt.Printf("first element address:%v, len:%d, cap:%d, %v\n",
	 &language[0], len(language), cap(language), language)
	language = append(language, "Golang", "Scala", "Lua")
	fmt.Printf("first element address:%v, len:%d, cap:%d, %v\n",
	 &language[0], len(language), cap(language), language)
}

在这里插入图片描述
for 循环的 range 形式可遍历切片或映射。当使用 for 循环遍历切片时,每次迭代都会返回两个值。第一个值为当前元素的下标,第二个值为该下标所对应元素的一份副本。

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
	for i, v := range pow {
		fmt.Printf("2**%d = %d\n", i, v)
	}
}

在这里插入图片描述
range也可以将下标或值赋予 _ 来忽略它,当只需要索引时可忽略第二个变量

func main() {
	pow := make([]int, 10)
	for i := range pow {
		pow[i] = 1 << uint(i) // == 2**i
	}
	for _, value := range pow {
		fmt.Printf("%d\n", value)
	}
}

在这里插入图片描述

映射

map 映射将键映射到值。映射的零值为 nil 。nil 映射既没有键,也不能添加键。
make 函数会返回给定类型的映射,并将其初始化备用。

type Person struct {
	Weight, Height float64
}
var m map[string]Person
func main() {
	m = make(map[string]Person)
	m["Bill"] = Person{
		70, 180,
	}
	fmt.Println(m["Bill"])
}

如果映射的元素类型相同,可以只在外层声明类型

type Person struct {
	Weight, Height float64
}
var m map[string]Person
func main() {
	m = map[string]Person{
		"Bill":{70, 180},
		"John":{85, 195},
	}
	fmt.Println(m)
}

在这里插入图片描述
可以获取修改删除映射元素,也可以使用双赋值检测某个key是否存在

type Person struct {
	Weight, Height float64
}
var m map[string]Person
func main() {
	m = map[string]Person{
		"Bill":{70, 180},
		"John":{85, 195},
		"Mary":{55, 168},
	}
	fmt.Println(m)
	fmt.Println(m["John"])
	m["Bill"] = Person{75, 180}
	fmt.Println(m)
	delete(m, "John")
	fmt.Println(m)
	param1, ok := m["Jack"]
	fmt.Println(param1, ok)
	param2, ok := m["Bill"]
	fmt.Println(param2, ok)
}

在这里插入图片描述

go 程

go中提供了轻量级的线程goroutine去执行函数,使用go 函数名执行。

import (
	"fmt"
	"time"
)
func say(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}
func main() {
	go say("world")
	say("hello")
}

信道

信道是带有类型的管道,通过make和chan关键字创建信道,通过信道操作符 <- 来发送或者接收值。
信道可以是 带缓冲的。将缓冲长度作为第二个参数提供给 make 来初始化一个带缓冲的信道,
仅当信道的缓冲区填满后,向其发送数据时才会阻塞。当缓冲区为空时,接受方会阻塞。

import "fmt"
func sum(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	c <- sum 
}
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 
	fmt.Println(x, y, x+y)
}

在这里插入图片描述
如果将上述代码改成

func main() {
	s := []int{7, 2, 8, -9, 4, 0}
	c := make(chan int, 1)
	sum(s[:len(s)/2], c)
	sum(s[len(s)/2:], c)
	x, y := <-c, <-c
	fmt.Println(x, y, x+y)
}

增加缓冲区同时去掉go程,则发生了锁冲突
在这里插入图片描述

Select

select 语句使一个 Go 程可以等待多个通信操作。select 会阻塞到某个分支可以继续执行为止,这时就会执行该分支。当多个分支都准备好时会随机选择一个执行。
当 select 中的其它分支都没有准备好时,default 分支就会执行。为了在尝试发送或者接收时不发生阻塞,可使用 default 分支:

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)
		}
	}
}

Mutex

Go 标准库中提供了 sync.Mutex 互斥锁类型及其两个方法:Lock Unlock
可以通过在代码前调用 Lock 方法,在代码后调用 Unlock 方法来保证一段代码的互斥执行。

type SafeCounter struct {
	v   map[string]int
	mux sync.Mutex
}
// Inc 增加给定 key 的计数器的值。
func (c *SafeCounter) Inc(key string) {
	c.mux.Lock()
	c.v[key]++
	c.mux.Unlock()
}
// Value 返回给定 key 的计数器的当前值。
func (c *SafeCounter) Value(key string) int {
	c.mux.Lock()
	defer c.mux.Unlock()
	return c.v[key]
}
func main() {
	c := SafeCounter{v: make(map[string]int)}
	for i := 0; i < 100; i++ {
		go c.Inc("key")
	}
	fmt.Println(c.Value("key"))
}

测试

go中测试相关的类在testing包下,编写测试函数有以下这些规则

  • 在xxx_test.go的文件中写
  • 函数名以Test开头
  • 参数只有一个 t *testing.T

类型为*testing.T的参数 t是测试函数的钩子,可以用t.Errorf打印格式化字符串信息同时使测试失败。
sum.go

func Sum(numbers []int) (sum int) {
	sum = 0
	for _, number := range numbers {
		sum += number
	}
	return
}

sum_test.go

func TestSum(t *testing.T) {
	a := []int{1, 2, 3, 4, 5}
	got := Sum(a)
	want := 15
	if got != want {
		t.Errorf("want '%d' and got '%d'", want, got)
	}
}

使用go test 命令执行测试
在这里插入图片描述
也可以使用go test -bench=.命令来执行基准测试,下面的基准测试表示执行了8021449次,每次144纳秒
在这里插入图片描述
同时可以使用go test -cover查看测试覆盖率
在这里插入图片描述

  • 0
    点赞
  • 2
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
<p style="text-align:center;"> <strong><span style="font-size:32px;"><br /> </span></strong> </p> <p style="text-align:left;"> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;color:#337FE5;">程序员转行首选Go </span></strong></span></strong> </p> <p style="text-align:left;"> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;color:#337FE5;">入职大厂快人一步</span></strong></span></strong> </p> <p style="text-align:left;"> <strong><span style="font-size:18px;"><span style="color:#337FE5;"><br /> </span></span></strong> </p> <p style="text-align:left;"> <span style="font-size:16px;">Go被称为“21世纪的C语言”,因其简洁的语法,以及自带的内存回收机制,使其可以拥有高速运</span><span style="font-size:16px;">行效率的同时,还能兼顾开发效率,所以越来越多大厂开始转投Go语言!</span> </p> <p style="text-align:center;"> <br /> </p> <p style="text-align:center;"> <br /> </p> <p style="text-align:left;"> <strong><span style="font-size:18px;color:#337FE5;"><strong><span style="font-size:18px;color:#337FE5;">转行学习误区多 </span></strong></span></strong> </p> <p style="text-align:left;"> <strong><span style="font-size:18px;color:#337FE5;"><strong><span style="font-size:18px;color:#337FE5;">学习效率Down到底</span></strong></span></strong> </p> <p style="text-align:left;"> <strong><span style="font-size:18px;color:#337FE5;"><br /> </span></strong> </p> <p style="text-align:left;"> <span style="font-size:16px;">在实际的开发工作中,有Java、PHP、Python、C/C++等编程语言基础的程序员,由于固有编程</span><span style="font-size:16px;">习惯的限制,很容易陷入学习误区,学习效率大大降低!</span> </p> <p style="text-align:left;"> <span style="font-size:16px;"><br /> </span> </p> <p style="text-align:center;"> <br /> </p> <p style="text-align:left;"> <span style="font-size:18px;"><img src="https://img-bss.csdnimg.cn/202011170520559519.png" alt="" /><br /> </span> </p> <p style="text-align:left;"> <span style="font-size:18px;"><br /> </span> </p> <p style="text-align:left;"> <span style="font-size:18px;"><br /> </span> </p> <p style="text-align:left;"> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;color:#337FE5;">站内首门专为转行打造 </span></strong></span></strong> </p> <p style="text-align:left;"> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;color:#337FE5;">程序员学Go不踩坑</span></strong></span></strong> </p> <p style="text-align:left;"> <strong><span style="font-size:18px;"><span style="color:#337FE5;"><br /> </span></span></strong> </p> <p style="text-align:left;"> <span style="font-size:16px;">《快速入门Go语言》,是站内首门专为程序员转行Go开发打造的必修课,课程详细讲解Go语言</span><span style="font-size:16px;">中必备的核心语法,以及Go中最重要的并发编程、切片及数组的使用等内容!</span> </p> <p style="text-align:left;"> <span style="font-size:16px;"><br /> </span> </p> <p style="text-align:center;"> <br /> </p> <p style="text-align:left;"> <span style="font-size:18px;"><img src="https://img-bss.csdnimg.cn/202011170522289181.png" alt="" /><br /> </span> </p> <p style="text-align:left;"> <span style="font-size:18px;"><br /> </span> </p> <p style="text-align:left;"> <span style="font-size:18px;"><br /> </span> </p> <p style="text-align:left;"> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;color:#337FE5;">课程逐级进阶 </span></strong></span></strong> </p> <p style="text-align:left;"> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;color:#337FE5;">快速提升Go语言编程思维</span></strong></span></strong> </p> <p style="text-align:left;"> <strong><span style="font-size:18px;"><span style="color:#337FE5;"><br /> </span></span></strong> </p> <p style="text-align:left;"> <span style="font-size:16px;">课程按知识点内容划分为先导篇、语法篇并发篇、网络篇、专项进阶篇、数据库编程篇,不只将</span><span style="font-size:16px;">知识点讲解透彻,更讲透为什么用、如何用,提升程序员Go语言的编程思维!</span> </p> <p style="text-align:left;"> <span style="font-size:16px;"><br /> </span> </p> <p style="text-align:center;"> <br /> </p> <p style="text-align:left;"> <span style="font-size:18px;"><img src="https://img-bss.csdnimg.cn/202011170523456090.png" alt="" /><br /> </span> </p>
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页

打赏

JustinNeil

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值