Go 语言(Golang)基础学习笔记(一)

教程推荐:

1.Go 语言教程
2.Go语言圣经(中文版)
3.Go语言高级编程
4.Go语言中文网
5.8小时转职Golang工程师(如果你想低成本学习Go语言)

1、Hello World

package main //包声明

import "fmt" //引入包

func main() {
      //函数
	fmt.Println("Hello, World!") //语句 & 表达式
}

Go 语言(Golang)基础学习笔记(一)_第1张图片

2、基础语法

<1> 字符串连接

Go 语言的字符串可以通过+ 实现:

package main //包声明

import "fmt" //引入包

func main() {
     
	fmt.Println("Hello, " + "World")
}

<2> 格式化字符串

package main

import (
	"fmt"
)

func main() {
     
	var stockCode = 123
	var endDate = "2020-12-31"
	// %d 表示整型数字,%s 表示字符串
	var url = "Code=%d&endDate=%s"
	var targetUrl = fmt.Sprintf(url, stockCode, endDate)
	fmt.Println(targetUrl)
}

Go 语言(Golang)基础学习笔记(一)_第2张图片

3、数据类型

类型 描述 例子
布尔型 true 或者 false var b bool = true
数字类型 整型 和浮点型 var stockCode int
字符串类型 字符序列 var endDate string

派生类型:

(a) 指针类型(Pointer)
(b) 数组类型
(c) 结构化类型(struct)
(d) Channel 类型
(e) 函数类型
(f) 切片类型
(g) 接口类型(interface(h) Map 类型

fmt格式占位符

fmt格式占位符

普通占位符
占位符     说明                           举例                   输出
%v      相应值的默认格式。            Printf("%v", people)   {
     zhangsan}%+v     打印结构体时,会添加字段名     Printf("%+v", people)  {
     Name:zhangsan}
%#v     相应值的Go语法表示            Printf("#v", people)   main.Human{
     Name:"zhangsan"}
%T      相应值的类型的Go语法表示       Printf("%T", people)   main.Human
%%      字面上的百分号,并非值的占位符  Printf("%%")            %
布尔占位符
占位符       说明                举例                     输出
%t          truefalsePrintf("%t", true)       true
整数占位符
占位符     说明                                  举例                       输出
%b      二进制表示                             Printf("%b", 5)             101
%c      相应Unicode码点所表示的字符              Printf("%c", 0x4E2D)%d      十进制表示                             Printf("%d", 0x12)          18
%o      八进制表示                             Printf("%d", 10)            12
%q      单引号围绕的字符字面值,由Go语法安全地转义 Printf("%q", 0x4E2D)        '中'
%x      十六进制表示,字母形式为小写 a-f         Printf("%x", 13)             d
%X      十六进制表示,字母形式为大写 A-F         Printf("%x", 13)             D
%U      Unicode格式:U+1234,等同于 "U+%04X"   Printf("%U", 0x4E2D)         U+4E2D

4、变量

Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。
声明变量的一般形式是使用 var 关键字:

<1> 变量声明var

仅指定变量类型,没有初始化,则变量默认为零值。

package main
import "fmt"
func main() {
     
	// 声明一个变量并初始化
	var a = "go"
	fmt.Println(a)

	// 没有初始化就为零值
	var b int
	fmt.Println(b)

	// bool 零值为 false
	var c bool
	fmt.Println(c)
}

Go 语言(Golang)基础学习笔记(一)_第3张图片
根据值自行判定变量类型:

var d = true
fmt.Println(d)

<2> 变量声明:=

package main
import "fmt"
func main() {
     
	str := "go"
	fmt.Println(str)
}

如果变量已经使用 var 声明过了,再使用 := 声明变量,就产生编译错误,格式:

str := "go" 相等于:var str = "go"

<3> 多变量声明

package main

import "fmt"

var x, y int
var (  // 这种因式分解关键字的写法一般用于声明全局变量
	a int
	b bool
)

var c, d int = 1, 2
var e, f = 123, "hello"

func main(){
     
	//这种不带声明格式的只能在函数体中出现
	g, h := 123, "hello"
	fmt.Println(x, y, a, b, c, d, e, f, g, h)
}

Go 语言(Golang)基础学习笔记(一)_第4张图片

<4> 值类型和引用类型

所有像 int、float、bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值:
Go 语言(Golang)基础学习笔记(一)_第5张图片

当使用等号 = 将一个变量的值赋值给另一个变量时,如:j = i,实际上是在内存中将 i 的值进行了拷贝:
Go 语言(Golang)基础学习笔记(一)_第6张图片
你可以通过&i 来获取变量 i 的内存地址,例如:0xf840000040(每次的地址都可能不一样)。值类型的变量的值存储在栈中。

package main

import "fmt"

func main(){
     
	str := "go"
	fmt.Println(str)
	fmt.Println(&str)
}

Go 语言(Golang)基础学习笔记(一)_第7张图片

<5> 常量

【1】const

const声明常量

const WIDTH int = 5  

【2】iota

iota是一个特殊常量,可以认为是一个可以被编译器修改的常量。

(1)默认使用

package main

import "fmt"

const (
	// 可以在const() 添加一个关键字 iota, 每行的iota都会累加1, 第一行的iota的默认值是0
	ID1  = iota  //iota = 0
	ID2   //iota = 1
	ID3  //iota = 2
)

func main() {
     
	fmt.Printf("ID1:%d\n", ID1)
	fmt.Printf("ID2:%d\n", ID2)
	fmt.Printf("ID3:%d\n", ID3)
}

Go 语言(Golang)基础学习笔记(一)_第8张图片

(2)构造表达式:

package main

import "fmt"

const (
	// 可以在const() 添加一个关键字 iota, 每行的iota都会累加1, 第一行的iota的默认值是0
	ID1  = 10*iota
	ID2
	ID3
)

func main() {
     
	fmt.Printf("ID1:%d\n", ID1)
	fmt.Printf("ID2:%d\n", ID2)
	fmt.Printf("ID3:%d\n", ID3)
}

Go 语言(Golang)基础学习笔记(一)_第9张图片

(3)每行累加1的特性

const (
	a, b = iota+1, iota+2 // iota = 0, a = iota + 1, b = iota + 2, a = 1, b = 2
	c, d                  // iota = 1, c = iota + 1, d = iota + 2, c = 2, d = 3
	e, f                  // iota = 2, e = iota + 1, f = iota + 2, e = 3, f = 4

	g, h = iota * 2, iota *3  // iota = 3, g = iota * 2, h = iota * 3, g = 6, h = 9
	i, k                       // iota = 4, i = iota * 2, k = iota * 3 , i = 8, k = 12
)

iota 只能够配合const() 一起使用, iota只有在const进行累加效果。

5 、运算符

Go 语言运算符

6、条件语句

<1> if else

package main

import "fmt"

func main() {
     
	a := 2
	if a == 0{
     

	}else if a == 1{
     

	}else{
     
		fmt.Println(a)
	}
}

<2> switch

方式一:switch {}

package main

import "fmt"

func main() {
     
	var grade string = "B"

	switch {
     
	case grade == "A":
		fmt.Printf("优秀!\n")
	case grade == "B", grade == "C":
		fmt.Printf("良好\n")
	case grade == "D":
		fmt.Printf("及格\n")
	case grade == "F":
		fmt.Printf("不及格\n")
	default:
		fmt.Printf("差\n")
	}
}

Go 语言(Golang)基础学习笔记(一)_第10张图片

方式二:switch v_name{}

package main

import "fmt"

func main() {
     
	var grade string = "B"

	switch grade {
     
	case "A":
		fmt.Printf("优秀!\n")
	case "B", "C":
		fmt.Printf("良好\n")
	case "D":
		fmt.Printf("及格\n")
	case "F":
		fmt.Printf("不及格\n")
	default:
		fmt.Printf("差\n")
	}
}

<3>select 语句

select 是 Go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收。

select 随机执行一个可运行的 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行。一个默认的子句应该总是可运行的。

7、循环语句

package main

import (
	"fmt"
	"strconv"
)

func main() {
     
	for i :=0;i<10;i++  {
     
		fmt.Printf(strconv.Itoa(i))
	}
}

Go 语言(Golang)基础学习笔记(一)_第11张图片

8、函数

<1> 函数定义

package main

import "fmt"

func main() {
     
	/* 定义局部变量 */
	var a int = 100
	var b int = 200
	var ret int

	/* 调用函数并返回最大值 */
	ret = max(a, b)

	fmt.Printf( "最大值是 : %d\n", ret )
}

/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
     
	/* 定义局部变量 */
	var result int

	if num1 > num2 {
     
		result = num1
	} else {
     
		result = num2
	}
	return result
}

Go 语言(Golang)基础学习笔记(一)_第12张图片

<2> 函数返回多个值:

package main

import "fmt"
// (x, y string) : 要传入的参数及类型
// (string, string) : 要返回的类型
func swap(x, y string) (string, string) {
     
	return y, x
}

func main() {
     
	a, b := swap("Google", "Runoob")
	fmt.Println(a, b)
}

Go 语言(Golang)基础学习笔记(一)_第13张图片

<3> 函数的多返回值三种写法

【1】匿名的返回值

//返回多个返回值,匿名的
func foo2(a string, b int) (int, int) {
     
    //...
    return 666, 777
}

【2】有形参名称的返回值

  • 返回 (r1 int, r2 int) ,此return后就不用再写了
//返回多个返回值, 有形参名称的
func foo3(a string, b int) (r1 int, r2 int) {
     
    //...

    //给有名称的返回值变量赋值
    r1 = 1000
    r2 = 2000
 
    return
}

返回值的类型相返回值还可以这样写

//返回多个返回值, 有形参名称的
func foo3(a string, b int) (r1 , r2  int) {
     
    //...

    //给有名称的返回值变量赋值
    r1 = 1000
    r2 = 2000
 
    return
}

当然 传入参数值的类型相返回值也可以这样写

//返回多个返回值, 有形参名称的
func foo3(a , b int) (r1 , r2  int) {
     
    //...

    //给有名称的返回值变量赋值
    r1 = 1000
    r2 = 2000
 
    return
}

<3>函数参数

函数如果使用参数,该变量可称为函数的形参。形参就像定义在函数体内的局部变量。调用函数,可以通过两种方式来传递参数:

传递类型 描述
值传递 值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递(传地址) 引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

引用传递:

package main

import "fmt"

func main() {
     
	/* 定义局部变量 */
	var a int = 100
	var b int= 200

	fmt.Printf("交换前,a 的值 : %d\n", a )
	fmt.Printf("交换前,b 的值 : %d\n", b )

	/* 调用 swap() 函数 交换地址
	 * &a 指向 a 指针,a 变量的地址
	 * &b 指向 b 指针,b 变量的地址
	 */
	swap(&a, &b)

	fmt.Printf("交换后,a 的值 : %d\n", a )
	fmt.Printf("交换后,b 的值 : %d\n", b )
}

func swap(x *int, y *int) {
     
	var temp int
	temp = *x    /* 保存 x 地址上的值 */
	*x = *y      /* 将 y 值赋给 x */
	*y = temp    /* 将 temp 值赋给 y */
}

Go 语言(Golang)基础学习笔记(一)_第14张图片

<4> 函数用法

函数用法 描述
函数作为另外一个函数的实参 函数定义后可作为另外一个函数的实参数传入
闭包 闭包是匿名函数,可在动态编程中使用
方法 方法就是一个包含了接受者的函数

[1] 函数作为另外一个函数的实参

package main

import (
	"fmt"
	"math"
)

func main(){
     
	/* 声明函数变量 */
	getSquareRoot := func(x float64) float64 {
     
		return math.Sqrt(x)
	}

	/* 使用函数 */
	fmt.Println(getSquareRoot(9))

}

Go 语言(Golang)基础学习笔记(一)_第15张图片

[2] 闭包

Go 语言支持匿名函数,可作为闭包。匿名函数是一个"内联"语句或表达式。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。

package main

import "fmt"

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

func main(){
     
	/* nextNumber 为一个函数,函数 i 为 0 */
	nextNumber1 := getSequence()

	/* 调用 nextNumber 函数,i 变量自增 1 并返回 */
	fmt.Println(nextNumber1()) // 输出 1
	fmt.Println(nextNumber1()) // 输出 2
	fmt.Println(nextNumber1()) // 输出 3

	/* 创建新的函数 nextNumber1,并查看结果 */
	nextNumber2 := getSequence()
	fmt.Println(nextNumber2()) // 输出 1
	fmt.Println(nextNumber2()) // 输出 2
}

Go 语言(Golang)基础学习笔记(一)_第16张图片

[3] 方法

Go 语言中同时有函数和方法。一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。

package main

import (
	"fmt"
)

// Circle  定义结构体 
type Circle struct {
     
	radius float64
}

func main() {
     
	var c1 Circle
	c1.radius = 10.00
	fmt.Println("圆的面积 = ", c1.getArea())
}

//该 method 属于 Circle 类型对象中的方法
func (c Circle) getArea() float64 {
     
	//c.radius 即为 Circle 类型对象中的属性
	return 3.14 * c.radius * c.radius
}

Go 语言(Golang)基础学习笔记(一)_第17张图片

9、数组

<1> 初始化固定长度数组

var n [10]int /* n 是一个长度为 10 的数组 */

var balance = [5]float32{
     1000.0, 2.0, 3.4, 7.0, 50.0}
var balance = [...]float32{
     1000.0, 2.0, 3.4, 7.0, 50.0}

//  将索引为 1 和 3 的元素初始化
balance := [5]float32{
     1:2.0,3:7.0}
package main

import "fmt"

func main() {
     
	var n [10]int /* n 是一个长度为 10 的数组 */
	var i,j int

	/* 为数组 n 初始化元素 */
	for i = 0; i < 10; i++ {
     
		n[i] = i + 100 /* 设置元素为 i + 100 */
	}

	/* 输出每个数组元素的值 */
	for j = 0; j < 10; j++ {
     
		fmt.Printf("Element[%d] = %d\n", j, n[j] )
	}
}

Go 语言(Golang)基础学习笔记(一)_第18张图片

<2> 编历方式

for i = 0; i < 10; i++ {
     
	fmt.Println("index = ", i, ", value = ", myArray[i])
}
for index, value := range myArray {
     
	fmt.Println("index = ", index, ", value = ", value)
}

_ 表示匿名变量

for _, value := range myArray {
     
	fmt.Println("index = ", index, ", value = ", value)
}

<3> 固定长度数组传参

package main

import "fmt"

func printData(arr [12]int){
     
	fmt.Println(arr)
}

func main() {
     
	myArray := [12]int{
     1,2,4,5}
	printData(myArray)
}

Go 语言(Golang)基础学习笔记(一)_第19张图片

若长度不匹配则报错
Go 语言(Golang)基础学习笔记(一)_第20张图片
所以此时最用动态数组。

<4> 动态数组

动态数组其实就是切片,请看12、Go 语言切片(Slice)

package main

import "fmt"

func printData(arr []int){
     
	fmt.Println(arr)
}

func main() {
     
	myArray := []int{
     1,2,4,5}
	printData(myArray)
}

Go 语言(Golang)基础学习笔记(一)_第21张图片

10、 指针

<1> 指针定义

一个指针变量指向了一个值的内存地址。

package main

import "fmt"

func main() {
     
	var a int= 20   /* 声明实际变量 */
	var ip *int        /* 声明指针变量 */

	ip = &a  /* ip的值赋为a的存储地址 */

	fmt.Printf("a 变量的值: %d\n", a)

	fmt.Printf("a 变量的地址是: %x\n", &a  )

	/* 指针变量的存储地址 */
	fmt.Printf("ip 变量的值: %x\n", ip )

	/* 使用指针访问值 */
	fmt.Printf("*ip 变量的值: %d\n", *ip )
}

Go 语言(Golang)基础学习笔记(一)_第22张图片
空指针:当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针。
nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。
一个指针变量通常缩写为 ptr。
空指针判断:

if(ptr != nil)     /* ptr 不是空指针 */
if(ptr == nil)    /* ptr 是空指针 */

<2> 指向指针的指针

如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。

当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址:

指向指针的指针变量声明格式如下:

var ptr **int;
package main

import "fmt"

func main() {
     
	var a int
	var ptr *int
	var pptr **int

	a = 3000
	ptr = &a
	pptr = &ptr

	fmt.Printf("a = %d\n", a)
	fmt.Printf("ptr = %d\n", ptr)
	fmt.Printf("*ptr = %d\n", *ptr)
	fmt.Printf("pptr = %d\n", pptr)
	fmt.Printf("*pptr = %d\n", *pptr)
	fmt.Printf("**pptr = %d\n", **pptr)
}

Go 语言(Golang)基础学习笔记(一)_第23张图片

<3> 指针作为函数参数

package main

import "fmt"

func main() {
     
	/* 定义局部变量 */
	var a int = 100
	var b int= 200

	fmt.Printf("交换前 a 的值 : %d\n", a )
	fmt.Printf("交换前 b 的值 : %d\n", b )

	/* 调用函数用于交换值
	 * &a 指向 a 变量的地址
	 * &b 指向 b 变量的地址
	 */
	swap(&a, &b);

	fmt.Printf("交换后 a 的值 : %d\n", a )
	fmt.Printf("交换后 b 的值 : %d\n", b )
}

func swap(x *int, y *int) {
     
	var temp int
	temp = *x    /* 保存 x 地址的值 */
	*x = *y      /* 将 y 赋值给 x */
	*y = temp    /* 将 temp 赋值给 y */
}

Go 语言(Golang)基础学习笔记(一)_第24张图片

11、 结构体(struct)

声明一种行的数据类型 myint, 是int的一个别名

type myint int

<1> 定义一个结构体

package main

import "fmt"

// Books 定义一个结构体
type Books struct {
     
	title   string
	author  string
	subject string
	bookId int
}

func main() {
     

	// 创建一个新的结构体
	book1 := Books{
     "Go 语言", "www.runoob.com", "Go 语言教程", 6495407}
	fmt.Println(book1)

	// 也可以使用 key => value 格式
	book2 := Books{
     title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", bookId: 6495407}
	fmt.Println(book2)

	// 忽略的字段为 0 或 空
	book3 := Books{
     title: "Go 语言", author: "www.runoob.com"}
	fmt.Println(book3)
}

Go 语言(Golang)基础学习笔记(一)_第25张图片

<2> 访问结构体成员

package main

import "fmt"

type Books struct {
     
	title string
	author string
	subject string
	bookId int
}

func main() {
     
	var Book1 Books        /* 声明 Book1 为 Books 类型 */
	var Book2 Books        /* 声明 Book2 为 Books 类型 */

	/* book1.描述 */
	Book1.title = "Go 语言"
	Book1.author = "www.runoob.com"
	Book1.subject = "Go 语言教程"
	Book1.bookId = 6495407

	/* book2.描述 */
	Book2.title = "Python 教程"
	Book2.author = "www.runoob.com"
	Book2.subject = "Python 语言教程"
	Book2.bookId = 6495700

	/* 打印 Book1 信息 */
	fmt.Printf( "Book1.title : %s\n", Book1.title)
	fmt.Printf( "Book1.author : %s\n", Book1.author)
	fmt.Printf( "Book1.subject : %s\n", Book1.subject)
	fmt.Printf( "Book1.bookId : %d\n", Book1.bookId)

	/* 打印 Book2 信息 */
	fmt.Printf( "Book2.title : %s\n", Book2.title)
	fmt.Printf( "Book2.author : %s\n", Book2.author)
	fmt.Printf( "Book2.subject : %s\n", Book2.subject)
	fmt.Printf( "Book2.bookId : %d\n", Book2.bookId)
}

Go 语言(Golang)基础学习笔记(一)_第26张图片

<3> 结构体作为函数参数

package main

import "fmt"

type Books struct {
     
	title string
	author string
	subject string
	book_id int
}

func main() {
     
	var Book1 Books        /* 声明 Book1 为 Books 类型 */

	/* book 1 描述 */
	Book1.title = "Go 语言"
	Book1.author = "www.runoob.com"
	Book1.subject = "Go 语言教程"
	Book1.book_id = 6495407

	/* 打印 Book1 信息 */
	printBook(Book1)
}

func printBook( book Books ) {
     
	fmt.Printf( "Book title : %s\n", book.title)
	fmt.Printf( "Book author : %s\n", book.author)
	fmt.Printf( "Book subject : %s\n", book.subject)
	fmt.Printf( "Book book_id : %d\n", book.book_id)
}

Go 语言(Golang)基础学习笔记(一)_第27张图片

<3> 结构体指针

package main

import "fmt"

type Books struct {
     
	title string
	author string
	subject string
	book_id int
}

func main() {
     
	var Book1 Books        /* 声明 Book1 为 Books 类型 */

	/* book 1 描述 */
	Book1.title = "Go 语言"
	Book1.author = "www.runoob.com"
	Book1.subject = "Go 语言教程"
	Book1.book_id = 6495407

	/* 打印 Book1 信息 */
	printBook(&Book1)
}
func printBook( book *Books ) {
     
	fmt.Printf( "Book title : %s\n", book.title)
	fmt.Printf( "Book author : %s\n", book.author)
	fmt.Printf( "Book subject : %s\n", book.subject)
	fmt.Printf( "Book book_id : %d\n", book.book_id)
}

Go 语言(Golang)基础学习笔记(一)_第28张图片

12、Go 语言切片(Slice)

Go 语言切片是对数组的抽象

Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片(“动态数组”)与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大

<1> 切片初始化

声明一个未指定大小的数组来定义切片:

数组初始化:

array := [3]int {
     1,2,3 }

切片初始化:

slice := []int {
     1,2,3 } 

直接初始化切片,[] 表示是切片类型,{1,2,3} 初始化值依次是 1,2,3,其 cap=len=3

【1】slice切片的4种声明定义方式

slice := []int {
     1,2,3 } 

2&3.切片不需要说明长度。或使用make() 函数(开辟空间)来创建切片:

var slice1 []type = make([]type, len)
也可以简写为
slice1 := make([]type, len)

3.也可以指定容量,其中 capacity 为可选参数。

make([]T, length, capacity)

<2>切片:把数组切成片

slice:= array[startIndex:endIndex] 
package main

import "fmt"

func main() {
     
	array := [5]int {
     1,2,3,4,5}

	slice := array[1:4]
	fmt.Println(slice)
}

Go 语言(Golang)基础学习笔记(一)_第29张图片

<3> len() 和 cap() 函数

  • 切片是可索引的,并且可以由 len()方法获取长度。

  • 切片提供了计算容量的方法cap() 可以测量切片最长可以达到多少。

package main

import "fmt"

func main() {
     
	arrayInt := []int{
     1,2,3,4}
	fmt.Printf("len=%d cap=%d slice=%v\n",len(arrayInt),cap(arrayInt),arrayInt)
}

Go 语言(Golang)基础学习笔记(一)_第30张图片

<4> 空(nil)切片

package main

import "fmt"

func main() {
     
	var numbers []int

	if numbers == nil {
     
		fmt.Printf("切片是空的")
	}
}

Go 语言(Golang)基础学习笔记(一)_第31张图片

<5> 切片截取

package main

import "fmt"

func main() {
     
	arrayInt := [] int {
     0,1,2,3,4,5,6}

	fmt.Println(arrayInt[1:4])
	//[:4] => [0:4]
	fmt.Println(arrayInt[:4])
	// [1:] => [1:len(arrayInt)]
	fmt.Println(arrayInt[1:])
}

Go 语言(Golang)基础学习笔记(一)_第32张图片

<6> append() 和 copy() 函数


package main

import "fmt"

func main() {
     
	var numbers []int
	printSlice(numbers)

	/* 允许追加空切片 */
	numbers = append(numbers, 0)
	printSlice(numbers)

	/* 向切片添加一个元素 */
	numbers = append(numbers, 1)
	printSlice(numbers)

	/* 同时添加多个元素 */
	numbers = append(numbers, 2,3,4)
	printSlice(numbers)

	/* 创建切片 numbers1 是之前切片的两倍容量*/
	numbers1 := make([]int, len(numbers), (cap(numbers))*2)

	/* 拷贝 numbers 的内容到 numbers1 */
	copy(numbers1,numbers)
	printSlice(numbers1)
}

func printSlice(x []int){
     
	fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

Go 语言(Golang)基础学习笔记(一)_第33张图片

13、范围(Range)

Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对。

package main
import "fmt"
func main() {
     
	//这是我们使用range去求一个slice的和。使用数组跟这个很类似
	nums := []int{
     2, 3, 4}
	sum := 0
	//我们不需要使用该元素的序号,所以我们使用空白符"_"省略了
	for _, num := range nums {
     
		sum += num
	}
	fmt.Println("sum:", sum)
	//在数组上使用range将传入index和值两个变量。
	for i, num := range nums {
     
		if num == 3 {
     
			fmt.Println("index:", i)
		}
	}
	//range也可以用在map的键值对上。
	kvs := map[string]string{
     "a": "apple", "b": "banana"}
	for k, v := range kvs {
     
		fmt.Printf("%s -> %s\n", k, v)
	}
	//range也可以用来枚举Unicode字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。
	for i, c := range "go" {
     
		fmt.Println(i, c)
	}
}

Go 语言(Golang)基础学习笔记(一)_第34张图片

13、Map(键值对集合)

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。

<1> 定义 Map

可以使用内建函数 make 也可以使用 map 关键字来定义 Map:
一般都要初始化值或用make开辟空间,开辟空间少了空间也会自动增

【1】仅声明map:

如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对,一般都要初始化值或用make开辟空间

// 声明变量,默认 map 是 nil 
var myMapName map[键的数据类型]值的数据类型
var myMap map[string]string

【2】声明并初始化map:

 myMap3 := map[string]string{
     
	"one":   "php",
	"two":   "c++",
	"three": "python",
}

【3】用make开辟空间:

// 使用 make 函数,
myMapName := make(map[键的数据类型]值的数据类型)
myMap := make(map[string]string)

myMap := make(map[string]string,len)
myMap := make(map[string]string,10)

<2> 通历Map

package main

import "fmt"

func main() {
     
	capitalMap := make(map[string]string)

	/* map插入key - value对,各个国家对应的首都 */
	capitalMap [ "France" ] = "巴黎"
	capitalMap [ "Italy" ] = "罗马"
	capitalMap [ "Japan" ] = "东京"
	capitalMap [ "India " ] = "新德里"

	/*使用键输出地图值 */
	for key,value := range capitalMap {
     
		fmt.Println(key, "首都是", value)
	}
}

Go 语言(Golang)基础学习笔记(一)_第35张图片

<3> 增删改查 和 delete() 函数

//增
capitalMap[ "France" ] = "巴黎"

//删
delete(countryCapitalMap, "France")

//改
capitalMap[ "France" ] = "巴黎2"

//查
fmt.Println(capitalMap[ "France" ])

delete() 函数:

package main

import "fmt"

func main() {
     
	/* 创建map */
	countryCapitalMap := map[string]string{
     "France": "Paris", "Italy": "Rome", "Japan": "Tokyo", "India": "New delhi"}

	fmt.Println("原始地图")

	/* 打印地图 */
	for country := range countryCapitalMap {
     
		fmt.Println(country, "首都是", countryCapitalMap [ country ])
	}

	/*删除元素*/ 
	delete(countryCapitalMap, "France")
	fmt.Println("法国条目被删除")

	fmt.Println("删除元素后地图")

	/*打印地图*/
	for country := range countryCapitalMap {
     
		fmt.Println(country, "首都是", countryCapitalMap [ country ])
	}
}

Go 语言(Golang)基础学习笔记(一)_第36张图片

<4> 引用传递

package main

import "fmt"

func ChangeValue(cityMap map[string]string) {
     
	cityMap["France"] = "巴黎2"
}

func main() {
     
	capitalMap := make(map[string]string)
	/* map插入key - value对,各个国家对应的首都 */
	capitalMap [ "France" ] = "巴黎"
	capitalMap [ "Italy" ] = "罗马"
	capitalMap [ "Japan" ] = "东京"
	capitalMap [ "India " ] = "新德里"

	ChangeValue(capitalMap)

	fmt.Println(capitalMap)
}

Go 语言(Golang)基础学习笔记(一)_第37张图片

14、 递归函数

递归,就是在运行的过程中调用自己。

<1> 阶乘

package main

import "fmt"

func Factorial(n uint64)(result uint64) {
     
	if n > 0 {
     
		result = n * Factorial(n-1)
		return result
	}
	return 1
}

func main() {
     
	var i int = 3
	fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(uint64(i)))
}

<2> 斐波那契数列

package main

import "fmt"

func fibonacci(n int) int {
     
	if n < 2 {
     
		return n
	}
	return fibonacci(n-2) + fibonacci(n-1)
}

func main() {
     
	var i int
	for i = 0; i < 10; i++ {
     
		fmt.Printf("%d\t", fibonacci(i))
	}
}

Go 语言(Golang)基础学习笔记(一)_第38张图片

15 类型转换

类型转换用于将一种数据类型的变量转换为另外一种类型的变量。
go 不支持隐式转换类型

package main

import "fmt"

func main() {
     
	var sum int = 17
	var count int = 5
	var mean float32

	mean = float32(sum)/float32(count)
	fmt.Printf("mean 的值为: %f\n",mean)
}

Go 语言(Golang)基础学习笔记(一)_第39张图片

16、接口

Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。

定义接口

package main

import (
	"fmt"
)
// NokiaPhone 定义一个结构体
type NokiaPhone struct {
     
}
// IPhone 定义一个结构体
type IPhone struct {
     
}

// Phone 定义了一个接口Phone
type Phone interface {
     
	call()
}

func (nokiaPhone NokiaPhone) call() {
     
	fmt.Println("This is NokiaPhone!")
}

func (iPhone IPhone) call() {
     
	fmt.Println("This is IPhone!")
}

func main() {
     
	var phone Phone

	//根据传入参数的类型调用不同的方法
	phone = new(NokiaPhone)
	phone.call()

	phone = new(IPhone)
	phone.call()

}

Go 语言(Golang)基础学习笔记(一)_第40张图片

17、错误处理

Go 语言通过内置的错误接口提供了非常简单的错误处理机制。
error类型是一个接口类型,这是它的定义:

type error interface {
     
    Error() string
}

我们可以在编码中通过实现 error 接口类型来生成错误信息。

函数通常在最后的返回值中返回错误信息。使用errors.New 可返回一个错误信息:

func Sqrt(f float64) (float64, error) {
     
    if f < 0 {
     
        return 0, errors.New("math: square root of negative number")
    }
    // 实现
}

实例:

package main

import (
	"fmt"
)

// DivideError 定义一个 DivideError 结构
type DivideError struct {
     
	dividee int
	divider int
}

// 实现 `error` 接口
func (de *DivideError) Error() string {
     
	strFormat := `
    Cannot proceed, the divider is zero.
    dividee: %d
    divider: 0
`
	return fmt.Sprintf(strFormat, de.dividee)
}

// Divide 定义 `int` 类型除法运算的函数
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
     
	if varDivider == 0 {
     
		dData := DivideError{
     
			dividee: varDividee,
			divider: varDivider,
		}
		errorMsg = dData.Error()
		return
	} else {
     
		return varDividee / varDivider, ""
	}

}

func main() {
     

	// 正常情况
	if result, errorMsg := Divide(100, 10); errorMsg == "" {
     
		fmt.Println("100/10 = ", result)
	}
	// 当除数为零的时候会返回错误信息
	if _, errorMsg := Divide(100, 0); errorMsg != "" {
     
		fmt.Println("errorMsg is: ", errorMsg)
	}

}

Go 语言(Golang)基础学习笔记(一)_第41张图片

18 、并发

<1> go 函数并发

并发:并行出发、并行执行
Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。
goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。
goroutine 语法格式

go 函数名( 参数列表 )

Go 允许使用 go 语句开启一个新的运行期线程, 即 goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。 同一个程序中的所有 goroutine 共享同一个地址空间。

package main

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

执行以上代码,你会看到输出的 hello 和 world 是没有固定先后顺序。因为它们是两个 goroutine 在执行:

package main

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("new 1")
	say("new 2")
}

Go 语言(Golang)基础学习笔记(一)_第42张图片

<2> 通道(channel)

通道(channel)是用来传递数据的一个数据结构。
通道可用于两个 goroutine(线程) 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。

ch <- v    // 把 v 发送到通道 ch
v := <-ch  // 从 ch 接收数据,并把值赋给 v

【1】定义通道

定义一个通道很简单,我们使用chan关键字即可,通道在使用前必须先创建:

ch := make(chan int)

注意:默认情况下,通道是不带缓冲区的。发送端发送数据,同时必须有接收端相应的接收数据。

以下实例通过两个 goroutine(线程) 来计算数字之和,在 goroutine(线程) 完成计算后,它会计算两个结果的和:

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 语言(Golang)基础学习笔记(一)_第43张图片

你可能感兴趣的:(程序开发,go语言)