Go语言学习

1、运行和解析

go run 命令已包含了编译和运行。它会先在一个临时目录编译程序,然后执行完后清理掉.
如果在run的后面加上 --work参数来查看临时目录。
go run --work  main.go

在这里插入图片描述
也可以通过go build命令来编译代码,执行后会生成一个可以执行文件,通过./XX直接执行
在这里插入图片描述

交叉编译

# 要去linux下执行 
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
# 要去Mac下执行 
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go
# 要去win下执行
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go

CGO_ENABLED : CGO 表示golang中的工具,CGO_ENABLED 表示CGO禁用,交叉编译中不能使用CGO的

GOOS
目标平台
mac 对应 darwin
linux 对应 linux
windows 对应 windows

GOARCH
目标平台的体系架构【386,amd64,arm】, 目前市面上的个人电脑一般都是amd64架构的
386 也称 x86 对应 32位操作系统
amd64 也称 x64 对应 64位操作系统
arm 这种架构一般用于嵌入式开发。 比如 Android , IOS , Win mobile , TIZEN 等

变量类型

:整型、浮点型、布尔型
变量声明:
标准声明 var 变量名称 变量类型 不需要分号
批量声明 var (变量名称 变量类型
变量名称 变量类型
变量名称 变量类型
… …)
变量初始化 var 变量名 类型 = 表达式 ,其中整型和浮点型变量默认值为0,布尔型变量默认为false,
初始化多个变量 var 变量名,变量名… = 表达式,表达式…
类型推导 var 变量名 = 表达式 ,编译器会根据表达式的值来推导变量名的类型并完成初始化
短变量声明 变量名 := 表达式
匿名变量 _一个下划线来表示
注意事项:
函数外的每个语句都必须以关键字开始(var、const、func等)
:=不能使用在函数外。
_多用于占位,表示忽略值。

常量 const

iota 常量计数器,在const关键字出现时将被重置为0。const中每新增一行常量声明将使iota计数一次
定义数量级 << 左移操作
多个iota定义在一行
基本类型
bool (布尔)
数值类型 分为有符号数和无符号数,有符号数可以用来表示负数,不同的位数代表它们实际存储占用空间,以及取值的范围
int8、int16、int32、int64、int
uint8、uint16、uint32、uint64、uint
float32, float64
complex64, complex128
byte
rune
string
类型转换,对显式类型非常严格,没有自动类型提升或转换

循环条件

For 循环语句用于重复执行一段代码,是 Go 中唯一可用的循环
for initialisation; condition; post {
}
break语句用于在 for 循环完成正常执行之前突然终止 for 循环,并将控件移动到 for 循环之后的代码行。
continue语句用于跳过 for 循环的当前迭代。在 continue 语句之后出现在 for 循环中的所有代码都不会在当前迭代中执行。循环将继续进行下一次迭代。

if else 是一个具有布尔条件的语句,如果该条件的计算结果为真 ,它将执行一段代码true。如果条件评估为 ,它会执行一个备用的 else 块false。

swich 是一个条件语句,它计算表达式并将其与可能匹配的列表进行比较并执行相应的代码块,switch 只要匹配中了就会中止剩余的匹配项,switch 的 case 条件可以是多个值, 同一个 case 中的多值不能重复。

数组

具有相同 唯一类型 的一组以编号且长度固定的数据项序列,数据的长度是固定的。我们在声明一个数组时需要指定它的长度,一旦指定了长度,那么它的长度值是不可以改变的。
数组声明,一个数组的表示形式为 T[n]。n 表示数组中元素的数量,T 代表每个元素的类型,可以忽略声明数组的长度,并用 … 代替,让编译器为你自动计算长度。
数组是值类型,而不是引用类型,当数组赋值给一个新的变量时,该变量会得到一个原始数组的一个副本,如果对新变量进行更改,则不会影响原始数组。

	o := [...]float64{67.4, 89.3, 21, 77}
	for i := 0; i < len(o); i++ {
		fmt.Println("%d th element of a is %.2f\n", i, o[i])
	}

使用 range 遍历数组 ,for 循环可用于遍历数组中的元素,range 返回索引和该索引处的值
for i, v := range a 利用的是 for 循环 range 方式
多维数组  [][] 数据类型 {}
j := [2][3]string{
		{"li", "wang", "oi"},
		{"cao", "sun", "hg"},
	}

	for _, v1 := range j {
		for _, v2 := range v1 {
			fmt.Println("%s", v2)
		}
	}

切片

是对数组一个连续片段的引用,是一个引用类型,是一个长度可变的数组,具有 T 类型元素的切片表示为[]T
使用语法 a[start:end] 创建一个从 a 数组索引 start 开始到 end - 1 结束的切片

a := [5]int{76, 77, 78, 79, 80}
	var b []int = a[1:4]
	fmt.Println(a)
	fmt.Println(b)

切片的修改:切片自己不拥有任何数据。它只是底层数组的一种表示。对切片所做的任何修改都会反映在底层数组中。

a := [5]int{76, 77, 78, 79, 80}
	var b []int = a[1:4]
	fmt.Println(a)
	fmt.Println(b)
	for g := range b {
		b[g]++
	}
	fmt.Println(a)

切片的长度和容量:
切片的长度是切片中的元素数。切片的容量是从创建切片索引开始的底层数组中元素数。

funarry := [...]string{"1", "2", "3", "4", "5"}
	funlist := funarry[1:4]
	fmt.Println(len(funlist), cap(funlist))

切片可以重置其容量。任何超出这一点将导致程序运行时抛出错误。

	funarry := [...]string{"1", "2", "3", "4", "5"}
	funlist := funarry[1:4]
	fmt.Println(len(funlist), cap(funlist))
	funlist = funlist[:cap(funlist)]
	fmt.Println(len(funlist), cap(funlist))

func make([]T,len,cap)[]T 通过传递类型,长度和容量来创建切片。容量是可选参数, 默认值为切片长度。make 函数创建一个数组,并返回引用该数组的切片。

r := make([]int, 5, 6)
	fmt.Println(r)

追加切片元素,使用 append 可以将新元素追加到切片上。append 函数的定义是 func append(s[]T,x … T)[]T。x … T 在函数定义中表示该函数接受参数 x 的个数是可变的。这些类型的函数被称为可变参函数。

car := []string{"福田", "宝马", "奔驰"}
	fmt.Println(car,len(car),cap(car))
	car = append(car, "雷克萨斯")
	fmt.Println(car,len(car),cap(car))

切片函数传递,切片包含长度、容量和指向数组第零元素的指针,切片原有空间不够时自动新建底层数组, 小于 1024, 新的容量直接翻倍增加

func subtactone(number []int) {
	for i := range number {
		number[i] -= 2
	}
}

nos := []int{8, 7, 6}
	fmt.Println(nos)
	subtactone(nos)
	fmt.Println(nos)

多维切片,与数组类似,可以有多个维度

pos := [][]string{
		{"c++", "java"},
		{"python", "goland"},
	}
	for _, v1 := range pos {
		for _, v2 := range v1 {
			fmt.Println(v2)
		}
	}

map

一种无序的键值对, 它是数据结构 hash 表的一种实现方式
map[type of key]type of value{xxxxxxxx}
make(map[type of key]type of value)

look := map[string]int{"code": 1, "msg": 333}
	fmt.Println(look)
	cm := make(map[string]int)
	cm["name"] = 22
	fmt.Println(cm)

map的零值是nil

var say map[string]int
	say["code"] = 10000
panic: assignment to entry in nil map

检索建的值 map[key]

citys := map[string]int{
		"北京": 110000,
		"广东": 430000,
	}
	city := "北京"
	postCode := citys[city]
	fmt.Println(city, postCode)

该映射将返回该元素类型的零值, 0 当我们尝试检索 Map中不存在的键的值时,不会出现运行时错误

citys := map[string]int{
		"北京": 110000,
		"广东": 430000,
	}
	city := "北京1"
	postCode := citys[city]
	fmt.Println(city, postCode)

检查键值是否存在 value, ok := map[key]

citys := map[string]int{
		"北京": 110000,
		"广东": 430000,
	}
	city := "北京"
	value, ok := citys[city]
	if ok == true {
		fmt.Println(value)
		postCode := citys[city]
		fmt.Println(city, postCode)
	}

遍历map中的所有元素 for循环的range形式用于迭代 Map的所有元素。

citys := map[string]int{
		"北京": 110000,
		"广东": 430000,
	}

	for key, value := range citys {
		fmt.Println(key, value)
	}

从map中删除元素 delete(map,key),函数没有返回值,删除 Map中不存在的键,则不会出现运行时错误。

citys := map[string]int{
		"北京": 110000,
		"广东": 430000,
	}

	delete(citys, "北京")

	for key, value := range citys {
		fmt.Println(key, value)
	}

与切片一样,maps 是引用类型。当一个 map 赋值给一个新的变量,它们都指向同一个内部数据结构。因此改变其中一个也会反映到另一个。
须指定 key, value 的类型,插入的纪录类型必须匹配。
key 具有唯一性,插入纪录的 key 不能重复。
KeyType 可以为基础数据类型(例如 bool, 数字类型,字符串), 不能为数组,切片,map,它的取值必须是能够使用 == 进行比较。
ValueType 可以为任意类型。
无序性。
线程不安全, 一个 goroutine 在对 map 进行写的时候,另外的 goroutine 不能进行读和写操作,Go 1.6 版本以后会抛出 runtime 错误信息。

字符串string

,通过将一组字符括在双引号中来创建字符串" "

%s 是打印字符串的格式说明符
%x 是十六进制的格式说明符
%b 是二进制的格式说明符
%d 是十进制的格式说明符
%o 是八进制的格式说明符
%t true或false
%c 格式说明符用于在printChars方法中打印字符串的字符
%T是用来输出数据类型的格式化占位符
%v输出所有的值信息

web := "https:www.gotribe.cn"
	fmt.Println(web)

字符串的单个字节

web := "https:www.gotribe.cn"
	fmt.Println(web)

	for i := 0; i < len(web); i++ {
		fmt.Println(web[i])
	}

在 UTF-8 编码中,一个码点可能会占一个以上的字节
rune 是Go 中的内置类型,它是 int32 的别名。Rune 表示 Go 中的 Unicode 代码点。代码点占用多少字节并不重要,它可以用一个符文来表示

web := "Señor"
	runes := []rune(web)
	for i := 0; i < len(runes); i++ {
		fmt.Printf("%c ", runes[i])
	}

字符串连接
使用+运算符

string1 := "1"
	string2 := "2"
	result := string1 + string2
	fmt.Println(result)
使用 fmt 包的Sprintf函数
string1 := "1"
	string2 := "2"
	string3 := "3"
	result := fmt.Sprintf("%x %x %s", string1, string2, string3)
	fmt.Println(result)

函数

是执行特定任务的代码块

func name(parameter) (result-list){
    //body
}

函数声明以func关键字开头,后跟name(函数名). 在括号中指定参数,后面为函数返回值result-list
指定参数的语法是,参数名称后跟类型。可以指定任意数量的参数,例如(parameter1 type, parameter2 type)。而{,}内的代码为函数的主体内容。
函数组成
函数名
参数列表(parameter)
返回值(result-list)
函数体(body)
参数和返回类型在函数中是可选的

单返回值函数

func plus(a, b int) (res int) {
	return a + b
}

count := plus(1, 3)
	fmt.Println(count)

多返回值函数,一个函数可以返回多个值

func multi() (string, int) {
	return "网", 2
}
name, age = multi()
	fmt.Println(name, age)

命名返回值,从函数返回命名值。如果返回值被命名,则可以认为它在函数的第一行被声明为变量。

func nameValue() (name string, height int) {
	// name = "王"
	// height = 110
	return
}

name, height := nameValue()
	fmt.Println(name, height)

参数可变函数

func sum(nums ...int) int {
	res := 0
	for _, v := range nums {
		res += v
	}
	return res
}
fmt.Println(sum(1))
	fmt.Println(sum(1, 2))
	fmt.Println(sum(1, 2, 3))

匿名函数

func(name string) {
		fmt.Println(name)
	}("web")

指针

是存储另一个变量的内存地址的变量。
指针的声明 指向类型 T 的指针用 *T 表示。
& 操作符用来获取一个变量的地址

package main

import (
	"fmt"
)

func main() {
	b := 255
	var a *int = &b
	fmt.Printf("%T \n", a)
	fmt.Println(a)
}

指针的空值,零值为nil

package main

import (
	"fmt"
)

func main() {
	b := 25
	var a *int
	if a == nil {
		fmt.Println(a)
		a = &b
		fmt.Println("is", b)
	}
}

使用新函数创建指针,new函数将一个类型作为参数并返回一个指针,该指针指向作为参数传递的类型的新分配的空值。

package main

import (
	"fmt"
)

func main() {
	c := new(int)
	fmt.Printf("%d   %T  %v", *c, c, c)
	*c = 50
	fmt.Println(" --- ", *c)
}

指针解引用,通过指针访问被指向的值。指针 a 的解引用表示为:*a

package main

import (
	"fmt"
)

func main() {
	a := 255
	b := &a
	fmt.Println(b)
	fmt.Println(*b)
	*b++
	fmt.Println(a)
}

向函数传递指针参数

package main

import (
	"fmt"
)

func role() *int {
	i := 5
	return &i
}

func main() {
	d := role()
	fmt.Println(*d)
}

不支持指针运算

package main

import (
	"fmt"
)

func role() *int {
	i := 5
	return &i
}

func main() {
	d := role()
	d++
	fmt.Println(*d)
}

Go语言学习_第1张图片

结构体

是由零个或多个任意类型的值聚合成的实体,它可以用于将数据分组为一个单元而不是将它们中的每一个作为单独的值。
声明一个结构体,关键字 type 和 struct 用来定义结构体

type StructName struct{
    FieldName type
}



package main

import (
	"fmt"
)

type Order struct {
	name string
	id   int
}

func main() {
	stu := Order{
		name: "王",
		id:   10000,
	}

	fmt.Println(stu)
	stu2 := Order{"中", 10001}
	fmt.Println(stu2)
}

创建匿名结构体,可以在不创建新数据类型的情况下声明结构。这些类型的结构称为匿名结构。

package main

import (
	"fmt"
)

func main() {
	temp := struct {
		name string
		age  int
	}{
		name: "王",
		age:  28,
	}
	fmt.Println(temp)
}

获取结构的各个字段,点.运算符用于访问结构的各个字段。

package main

import (
	"fmt"
)

func main() {
	temp := struct {
		name string
		age  int
	}{
		name: "王",
		age:  28,
	}
	fmt.Println(temp.name, temp.age)
}

结构体的指针,可以创建指向结构的指针。

package main

import (
	"fmt"
)

type Employee struct {
	name string
	age  int
}

func main() {
	temp := &Employee{
		name: "wang",
		age:  80,
	}

	fmt.Println((*temp).name)
	fmt.Println((*temp).age)
}

匿名字段,创建具有仅包含类型而没有字段名称的字段的结构

package main

import (
	"fmt"
)

type Employee struct {
	string
	int
}

func main() {
	temp := &Employee{
		string: "wang",
		int:    80,
	}

	fmt.Println((*temp).string)
	fmt.Println((*temp).int)
}

嵌套结构体,一个结构可能包含一个字段,而该字段又是一个结构

package main

import (
	"fmt"
)

type Address struct {
	city  string
	state string
}

type Person struct {
	name    string
	age     int
	address Address
}

func main() {
	temp := Person{
		name: "wang",
		age:  90,
		address: Address{
			city:  "gd",
			state: "Y",
		},
	}
	fmt.Println(temp.name)
	fmt.Println(temp.age)
	fmt.Println(temp.address.city)
	fmt.Println(temp.address.state)
}

当定义一个结构体变量,但是没有给它提供初始值,则对应的字段被赋予它们各自类型的零值。

方法

方法的声明
方法(method)的声明和函数很相似, 只不过它必须指定接收者:

func (t T) F() {}

注意:
接收者的类型只能为用关键字 type 定义的类型,例如自定义类型,结构体。
同一个接收者的方法名不能重复 (没有重载),如果是结构体,方法名还不能和字段名重复。
值作为接收者无法修改其值,如果有更改需求,需要使用指针类型。

package main

import (
	"fmt"
)

type Employee struct {
	name     string
	salary   int
	currency string
}

func (e Employee) displaySalary() {
	fmt.Println(e.name, e.currency, e.salary)
}

func main() {
	emp := Employee{
		name:     "joyous",
		salary:   100,
		currency: "$",
	}
	emp.displaySalary()
}

指针接收器与值接收器型

package main

import (
	"fmt"
)

type Employee struct {
	name string
	age  int
}

func (e *Employee) changeName(newName string) {
	e.name = newName
}

func (e *Employee) changeAge(newAge int) {
	e.age = newAge
}

func main() {
	e := Employee{
		name: "joyous",
		age:  20,
	}
	fmt.Println(e.name, e.age)
	e.changeName("joyous li")
	e.changeAge(25)
	fmt.Println(e.name, e.age)
}

changeName 方法有一个值接收器 (e Employee),而 changeAge 方法有一个指针接收器 (e *Employee)。在 changeName 中对 Employee 结构体的 name 字段所做的更改对调用者是不可见的,因此程序会在方法 e 之前和之后打印相同的 name。因为 changeAge 方法有一个指针接收器 (e *Employee),所以在方法调用 (&e) 之后对 age 字段所做的更改 (51) 将对调用者可见。

你可能感兴趣的:(Go,学习,golang,学习,开发语言)