1.golang介绍

1.1go语言介绍

Golang是Google的三个人开发的一种静态强类型、编译型语言。Go语言语法与C相近,但功能上有:内存安全,GC(垃圾回收),结构形态及CSP-style并发计算

强类型语言也称为强类型定义语言。是一种总是强制类型定义的语言,要求变量的使用要严格符合定义,所有变量都必须先定义后使用。通俗的说就是:强类型语言在编译前就把数据类型确定了,被确定了数据类型的变量,如果不强制转换,就永远是给定的数据类型。比如:Java、C/C++等都是强类型语言。

弱类型语言也称为弱类型定义语言。与强类型定义相反。简单来说:弱类型语言是在编译后确定数据类型,没有明显的类型,他能随着环境的不同,自动变换类型。比如:python、VB、JS、PHP等都是弱类型语言。

1.2Go语言特点

背靠大厂,google背书,可靠
天生支持并发(最显著特点)
语法简单,容易上手
内置runtime,支持垃圾回收
可直接编译成机器码,不依赖其他库
丰富的标准库
跨平台编译

1.3go语言的应用领域

go语言的应用领域

2测试golang

安装好golang解释器跟语言后先测试是否正常
打开golang创建一个go文件在里面输入

package main // 声明 main 包 创建go文件会自动声明
import "fmt" // 导入 fmt 包,打印字符串时需要用到
func main() {  // 声明 main 主函数入口
	fmt.Println("hello Go lang ") // 打印 字符串
}

如果运行后出现以下效果说明正常

golang gin clientip remoteip 区别_字符串

3.golang的语法使用

3.1变量和常量

3.1.1变量的定义及变量作用域

注意:golang里边不能用单引号’',只能用双引号""
声明变量两种形式 1:var aa string = “hello”
2: b := 2 不用指定类型 如果在2加上""就是字符串类型,不加整形类型

package main // 声明 main 包 创建go文件会自动声明
import "fmt" // 导入 fmt 包,打印字符串时需要用到
var a int = 1  // 在最外层定义的是全局变量
var aa string = "hello"
func main() {
	b := 2    // 声明变量的第二种 不用指定类型 如果在2加上""就是字符串类型
	var m, n = 1, 2
	fmt.Println("变量定义a", a)
	fmt.Println("变量定义aa", aa)
	fmt.Println("变量定义b", b)
	fmt.Println("变量定义m,n", m, n)
	fmt.Println("变量定义m,n", &a)
}

golang gin clientip remoteip 区别_jvm_02

3.1.2常量const

package main // 声明 main 包 创建go文件会自动声明
import "fmt" // 导入 fmt 包,打印字符串时需要用到
func main() {
	const a int = 1
	fmt.Println(a)
}
func main() {
	fmt.Println("内容","内容")//输出内容后换行
	fmt.Print("内容","内容")//输出内容后不换行
	fmt.Printf("verb","内容")//根据verb输出指定格式内容
}

3.1.3系统关键字

var和const :变量和常量的声明
var varName type  或者 varName : = value
package and import: 导入
func: 用于定义函数和方法
return :用于从函数返回
defer someCode :在函数退出之前执行
go : 用于并行
select 用于选择不同类型的通讯
interface 用于定义接口
struct 用于定义抽象数据类型
break、case、continue、for、fallthrough、else、if、switch、goto、default 流程控制
chan用于channel通讯
type用于声明自定义类型
map用于声明map类型数据
range用于读取slice、map、channel数据

3.2函数

函数声明包括函数名、形式参数列表、返回值列表以及函数体
可以进行传参 传参的时候指明类型

func 函数名 (参数列表) (返回值列表){
    函数体
}
func add(a int, b int) int {
	return a + b
}
func main() {
	fmt.Println("hello world")
	c := add(1, 2)
	fmt.Println(c)
}

3.2.1defer

延迟语句,延迟一个函数的执行
 一般用于文件的关闭,临时文件的删除
 语法:
 defer close()
 可以在函数中定义多个defer,按照逆序执行,特别是你在进行一些打开资源的时候,遇到错误提前返回,在返回前可以做关闭资源的操作,不然容易资源泄露
 多个defer采用的后进先出(栈的数据结果),后defer的先执行,先defer的后执行

如果两个都加上defer最后一个(f2)先执行

package main
import (
	"fmt"
)
func f1() {
	fmt.Println("f1")
}
func f2() {
	fmt.Println("f2")
}
func main() {
	defer f1()
	defer f2()
}

golang gin clientip remoteip 区别_golang_03


如果只有一个加了defer那么加了 的defer的后执行

func main() {
	defer f2()
	f1()
}

golang gin clientip remoteip 区别_java_04

3.2.2传递参数

先传递参数,在执行前已经传递
在f1()执行前就已经将变量 a:=2传递过去了,执行时输出的是2不是3

package main
import (
	"fmt"
)
func f1(a int) {
	fmt.Println("f1:", a)
}
func f2() {
	fmt.Println("f2")
}
func main() {
	a := 2
	defer f1(a)
	a++
	defer f2()
	fmt.Println("main:", a)
}

golang gin clientip remoteip 区别_字符串_05

3.2.3匿名函数

没有名字的函数,通常只能被调用一次

package main
import (
	"fmt"
)
func f1() {
	fmt.Println("f1")
}
func main() {
	f1()
	f2 := f1
	f2()
	func (){
		fmt.Println("匿名函数")
	}()
}

golang gin clientip remoteip 区别_字符串_06


带参数的多次使用匿名函数

package main
import (
	"fmt"
)
func main() {
	fun3 := func(a, b int) int {
		return a + b
	}
	res1 := fun3(1, 2)
	fmt.Println(res1)
}

golang gin clientip remoteip 区别_java_07

3.3循环和判断

3.3.1循环遍历

package main
import (
	"fmt"
)
var a int = 10
func main() {
	// fmt.Println(a)
	//从0到0
	for i := 0; i < a; i++ {
		fmt.Println(i)
	}
	fmt.Println("i写在里面")
  //从1到10
	for i := 0; i < a; {
		i++
		fmt.Println(i)
	}
  for k, v := range []int{1, 2, 3} {
		fmt.Println("k,v:", k, v)
	}
}

效果演示代码有点长就截取了最后一段

golang gin clientip remoteip 区别_字符串_08

3.3.2判断

if 条件判断语句 {
    执行语句
  }else if 条件判断语句{
     执行语句
  }....
  else{
    执行语句
  }
例子:
package main
import (
	"fmt"
)
var a int = 10
func main() {
	// fmt.Println(a)
	for i := 0; i < a; i++ {
		if i == 3 {
			fmt.Println(i)
		} else if i == 6 {
			fmt.Println(i)
		} else {
			fmt.Println("tttt", i)
		}
	}
}

golang gin clientip remoteip 区别_golang_09

3.4支持的数据类型

3.4.1printf格式化输出

有两种输出方式 一种是println输出还有一种就是printf输出

%%	一个%字面量
%b	一个二进制整数值(基数为 2),或者是一个(高级的)用科学计数法表示的指数为 2 的浮点数
%c	字符型。可以把输入的数字按照 ASCII 码相应转换为对应的字符
%d	一个十进制数值(基数为 10)
%f	以标准记数法表示的浮点数或者复数值
%o	一个以八进制表示的数字(基数为 8)
%p	以十六进制(基数为 16)表示的一个值的地址,前缀为 0x,字母使用小写的 a-f 表示
%q	使用 Go 语法以及必须时使用转义,以双引号括起来的字符串或者字节切片[]byte,或者是以单引号括起来的数字
%s	字符串。输出字符串中的字符直至字符串中的空字符(字符串以’\0‘结尾,这个’\0’即空字符)
%t	以 true 或者 false 输出的布尔值
%T	使用 Go 语法输出的值的类型
%x	以十六进制表示的整型值(基数为十六),数字 a-f 使用小写表示
%X	以十六进制表示的整型值(基数为十六),数字 A-F 使用小写表示

3.4.2整形 int

整形顾名思义,就是存储的数据类型是整数,Go lang中分为有符号和无符号,简单理解就是存储范围上的差异:
有符号整型:int8、int16、int32、int64。
无符号整型:uint8、uint16、uint32、uint64。
特定CPU平台机器字大小的有符号和无符号的int和uint,32或64字节。不同的编译器在相同的硬件平台上可能产生不同的大小。

package main

import (
	"fmt"
	"math"
	"unsafe"
)
// 有符号整型
func Integer() {
	var num8 int8 = 127
	var num16 int16 = 32767
	var num32 int32 = math.MaxInt32
	var num64 int64 = math.MaxInt64
	var num int = math.MaxInt
	fmt.Printf("num8的类型是 %T, num8的大小 %d, num8是 %d\n",
		num8, unsafe.Sizeof(num8), num8)
	fmt.Printf("num16的类型是 %T, num16的大小 %d, num16是 %d\n",
		num16, unsafe.Sizeof(num16), num16)
	fmt.Printf("num32的类型是 %T, num32的大小 %d, num32是 %d\n",
		num32, unsafe.Sizeof(num32), num32)
	fmt.Printf("num64的类型是 %T, num64的大小 %d, num64是 %d\n",
		num64, unsafe.Sizeof(num64), num64)
	fmt.Printf("num的类型是 %T, num的大小 %d, num是 %d\n",
		num, unsafe.Sizeof(num), num)
}
// 无符号整型
func unsignedInteger() {
	var num8 uint8 = 128
	var num16 uint16 = 32768
	var num32 uint32 = math.MaxUint32
	var num64 uint64 = math.MaxUint64
	var num uint = math.MaxUint
	fmt.Printf("num8的类型是 %T, num8的大小 %d, num8是 %d\n",
		num8, unsafe.Sizeof(num8), num8)
	fmt.Printf("num16的类型是 %T, num16的大小 %d, num16是 %d\n",
		num16, unsafe.Sizeof(num16), num16)
	fmt.Printf("num32的类型是 %T, num32的大小 %d, num32是 %d\n",
		num32, unsafe.Sizeof(num32), num32)
	fmt.Printf("num64的类型是 %T, num64的大小 %d, num64是 %d\n",
		num64, unsafe.Sizeof(num64), num64)
	fmt.Printf("num的类型是 %T, num的大小 %d, num是 %d\n",
		num, unsafe.Sizeof(num), num)
}
func main() {
	Integer()
	println("---------------------------------------")
	unsignedInteger()
}

golang gin clientip remoteip 区别_golang_10

3.4.3浮点数

package main
import (
	"fmt"
	"math"
)
func showFloat() {
	var num1 float32 = math.MaxFloat32
	var num2 float64 = math.MaxFloat64
	fmt.Printf("num1的类型是%T,num1是%g\n", num1, num1)
	fmt.Printf("num2的类型是%T,num1是%g\n", num2, num2)
}
func main() {
	showFloat()
}

golang gin clientip remoteip 区别_字符串_11

3.4.4字符 byte/rune

golang中byte数据类型与rune相似,它们都是用来表示字符类型的变量类型。它们的不同在于:
byte 等同于int8,常用来处理ascii字符
rune 等同于int32,常用来处理unicode或utf-8字符

package main
import (
	"fmt"
)
func main() {
	var a byte = 66
	fmt.Printf("%c", a)
}

func main() {
	var str = "中国"
	fmt.Println("len:", len([]rune(str)))
}

第一个main()效果图

golang gin clientip remoteip 区别_golang_12


第二个main()效果图

golang gin clientip remoteip 区别_数组_13

3.4.5string
package main
import (
	"fmt"
)
func main() {
	var str = "中国"
	ttt := "你好"
	fmt.Println(str)
	fmt.Println(ttt)
}

golang gin clientip remoteip 区别_java_14

3.4.6布尔类型
package main
import (
	"fmt"
)
func main() {
	a :=true
	b :=false 
	fmt.Println("ab:",a,b)
}

golang gin clientip remoteip 区别_字符串_15

3.5复合数据类型

3.5.1数组

func main() {
	//定义数组 var 名字 [长度]类型
	var arr [3]int
	arr[0] = 1
	arr[2] = 10
	fmt.Println(arr)
	//定义多维数组
	marr := [3][2]int{{1, 2}, {3, 4}}
	fmt.Println(marr[0][0])
	// 直接使用 ... 让编译器为我们计算该数组的长度
	arr5 := [...]int{15, 20, 25, 30, 35, 40}
	fmt.Println(arr5)
}

golang gin clientip remoteip 区别_字符串_16


数组遍历

func main() {
	//数组遍历
	arr := [3]string{"zs", "lishi"}
	for _, v := range arr {
		fmt.Println(v)
	}
	//定义多维数组
	marr := [3][2]int{{1, 2}, {3, 4}}
	for _, v := range marr {
		for j, val := range v {
			fmt.Println("i,v:", j, val)
		}
	}
}

golang gin clientip remoteip 区别_字符串_17


数组是值类型 ,而不是引用类型。这意味着当它们被分配给一个新变量时,将把原始数组的副本分配给新变量。如果对新变量进行了更改,则不会影响原对象

func main() {
	//数组遍历
	arr := [3]string{"zs", "lishi"}
	b := arr
	b[0] = "2222"
	fmt.Println(arr)
	fmt.Println(b)
}

golang gin clientip remoteip 区别_java_18

3.5.2 切片(Slice)

Slice代表变长的序列,每个元素都有相同的类型,是引用类型。和数组很像,没有固定长度。Slice的底层引用了一个数组对象。由三部分构成:指针、长度和容量。指针指向第一个slice元素对应的底层数组元素的地址,长度就是元素的字数。容量是从开始位置到底层数据的结尾位置。len和cap返回长度和容量,初始化是长度必须小于容器

func main() {
	// 声明整型切片
	var numList []int
	// 声明一个空切片
	var numListEmpty = []int{}
	//make声明 make([]Type, size, cap) :
	// 3是容量能放3个 5是最大容量 最多可放五个
	numlist := make([]int, 3, 5)
}

遍历

// 3是容量能放3个 5是最大容量 最多可放五个
numlist := make([]int, 3, 5)
	numlist[0] = 10000
	numlist[1] = 10
	numlist[2] = 1
	for i, v := range numlist {
		fmt.Println(i, v)
	}

golang gin clientip remoteip 区别_字符串_19


常用方法

func main() {
	numlist := make([]int, 3, 5)
	numlist[0] = 10000
	numlist[1] = 10
	numlist[2] = 1
	//切片没有填入起始值和结束值,默认就是 0 和 len(arr)
	fmt.Println(numlist[:])
	//左包含右不包含
	fmt.Println(numlist[0:2])
	//添加append,当新的元素被添加到切片时,如果容量不足,会创建一个新的数组。现有数组的元素被复制到这个新数组中,并返回新的引用。现在新切片的容量是旧切片的两倍
	numlist = append(numlist, 5)
	fmt.Println(numlist[:])
 	//切片也可以有多个维度,也就是嵌套的形式
	clicearr := [][]int{{1, 2}, {3, 4}}
	clicearr[0][0] = 10
	fmt.Println(clicearr[0][0])
}

golang gin clientip remoteip 区别_java_20

3.5.3map

在 Go lang中,集合是散列表(哈希表)的引用。它是一个拥有键值对元素的无序集合,在这个集合中,键是唯一的,可以通过键来获取、更新或移除操作。无论这个散列表有多大,这些操作基本上是通过常量时间完成的。所有可比较的类型,如整型 ,字符串等,都可以作为 key 。属于引用类型
使用 make方法传入键和值的类型,可以创建集合 。具体语法为 make(map[KeyType]ValueType) 。

func main() {
	//make创建
	stu := make(map[int]string)
	stu[1] = "zs"
	stu[2] = "li"
	fmt.Println(stu)
	//map创建
	ages := map[string]int{}
	ages["asdf"] = 2
	fmt.Println(ages)
}

golang gin clientip remoteip 区别_golang_21


常用方法

func main() {
	//make创建
	stu := make(map[int]string)
	stu[1] = "zs"
	stu[2] = "li"
	fmt.Println(stu)
	//map创建
	ages := map[string]int{}
	//添加
	ages["abc"] = 3
	ages["abcd"] = 31
	fmt.Println(ages)
	//修改
	ages["abcd"] = 2
	//删除
	delete(ages, "abc")
	fmt.Println(ages)
	//判断某个key是否存在
	val, ok := ages["abcd"]
	fmt.Println(val)
	fmt.Println(ok)
	//遍历
	for k, v := range stu {
		fmt.Println("k,v:", k, v)
	}
}

golang gin clientip remoteip 区别_golang_22

3.5.4结构体

结构体是一种聚合的数据类型,由零个或多个做任意类型的值聚合成的实体,每个值称为结构体的成员。比如员工信息

type 名称 struct{
		字段名 字段类型
}
type Stu struct {
  ID       int
  Name     string
  Birthday time.Time
  Score    int
}
var stu Stu
stu.Name = "xiaoming"
stu.Score += 10
fmt.Println(stu)
方法二:
type Stu struct{
	id int
	name string
	age int
}
func main() {
	stu := Stu{
		id: 1,
		name: "学习Go lang,并完成web开发任务",
		age:1,
	}
	fmt.Println(stu)
}

3.5.5指针类型

指针是存储另一个变量的内存地址的变量。变量是一种使用方便的占位符,用于引用计算机内存地址,一个指针变量可以指向任何一个值的内存地址它指向那个值的内存地址。类比的话,指针就是书籍中的目录,本身也占据书页,既可以通过目录获得章节内容,又可以指向具体章节的页数(地址)

package main
import "fmt"
func main() {
	var a int = 20 /* 声明实际变量 */
	var ip *int    /* 声明指针变量 */
	ip = &a /* 指针变量的存储地址 */
	fmt.Printf("a 变量的地址是: %x\n", &a)
	/* 指针变量的存储地址 */
	fmt.Printf("ip 变量的存储地址: %x\n", ip)
	/* 使用指针访问值 */
	fmt.Printf("*ip 变量的值: %d\n", *ip)
}

golang gin clientip remoteip 区别_jvm_23

3.6深拷贝浅拷贝

3.6.1定义

深拷贝 拷贝的是数据本身。值类型的数据,默认的都是深拷贝 array int float string bool struct
浅拷贝 拷贝的是数据地址。多个变量指向同一块内存。引用类型默认都是浅拷贝:slice map

3.6.2案例

package main
import (
	"fmt"
)
func main() {
	//深拷贝值类型
	a := 1
	b := a
	fmt.Println(a)
	fmt.Println(b)
	a = 10
	fmt.Println(a)
	fmt.Println(b)
	//浅拷贝引用类型
	m := []int{1, 2, 3}
	n := m[0:2]
	fmt.Println(m)
	fmt.Println(n)
	m[0] = 10
	fmt.Println(m)
	fmt.Println(n)
	//切片深拷贝实现
	s1 := []int{1, 2, 3, 4}
	s2 := make([]int, 0)
	for i := 0; i < len(s1); i++ {
		s2 = append(s2, s1[i])
	}
	fmt.Println(s1)
	fmt.Println(s2)
	s1[0] = 100
	fmt.Println(s1)
	fmt.Println(s2)
	
}

golang gin clientip remoteip 区别_数组_24

3.6.3copy实现切片深拷贝

package main
import (
	"fmt"
)
func main() {
	s2 := []int{7, 8}
	s3 := []int{2, 3, 4}
	// copy(s3, s2) //将s2中的数据拷贝到s3
	copy(s2, s3) //将s3中的数据拷贝到s2
	s3[0] = 100
	fmt.Println(s2)
	fmt.Println(s3)
}

golang gin clientip remoteip 区别_字符串_25

go语言语法练习题

找出100以内的偶数

//找出100以内的偶数
func main() {
	for i := 0; i < 100; i++ {
		if i%2 == 0 {
			fmt.Println(i)
		}
	}
}

数据过长只截取了一部分

golang gin clientip remoteip 区别_jvm_26


查找出100以内的质数

质数也就是只能被1和自己本身的数整除的数字

// 查找出100以内的质数
func main() {
	for i := 2; i < 100; i++ {
		flag := true
		for j := 2; j < i; j++ {
			if i%j == 0 {
				flag = false
				//break
			}
		}
		if flag == true {
			fmt.Println(i)
		}
	}
}

golang gin clientip remoteip 区别_数组_27

且前输出及降序升序排序

type Person struct {
	Age int
}
func main() {
	// 切片输出
	//num_list := make([]int, 100, 100)
	person := make([]*Person, 0)
	status := 0
	for i := 2; i < 100; i++ {
		num := 0
		for j := 2; j < 100; j++ {
			if i%j == 0 {
				num++
			}
		}
		if num < 2 {
			//num_list[status] = i
			person = append(person, &Person{
				Age: i,
			})
			//fmt.Println(person)
			status++
		}
	}
	list2 := make([]int, status, status+10)
	i := 0
	for _, item := range person {
		//fmt.Printf("Age: %d\n", item.Age)
		list2[i] = item.Age
		i++
	}
	fmt.Println(list2)
	// 切片排序
	list3 := []int{2, 3, 10, 20, 5}
	//升序
	sort.Ints(list3)
	fmt.Printf("升序:%v\n", list3)
	// 降序
	sort.Sort(sort.Reverse(sort.IntSlice(list3)))
	fmt.Printf("降序:%v\n", list3)

	// 3.冒泡排序实现[2,10,8,6,5],输出结果为[2,5,6,8.10]
	var arr = []int{2, 10, 8, 6, 5}
	for i := 0; i < len(arr)-1; i++ {
		for j := 0; j < len(arr)-i-1; j++ {
			if arr[j] > arr[j+1] {
				temp := arr[j]
				arr[j] = arr[j+1]
				arr[j+1] = temp
			}
		}
	}
	fmt.Println(arr)
}

冒号排序

// 冒号排序
func sort1(arr []int) []int {
	tcount := len(arr)
	if tcount <= 1 {
		return arr
	}
	for i := 0; i < tcount; i++ {
		for j := i + 1; j < tcount; j++ {
			if arr[i] > arr[j] {
				arr[i], arr[j] = arr[j], arr[i]
			}
		}
	}
	return arr
}
func main() {
	arr := []int{1, 2, 8, 19, 6, 5}
	fmt.Println(arr)
	res := sort1(arr)
	fmt.Println(res)
}

golang gin clientip remoteip 区别_jvm_28

冒号排序和二分查找

package main

import "fmt"

// 冒泡排序
func sort(arr []int) []int {
	counts := len(arr)
	if counts <= 1 {
		return arr
	}
	for i := 0; i < counts; i++ {
		for j := i + 1; j < counts; j++ {
			if arr[i] > arr[j] {
				arr[i], arr[j] = arr[j], arr[i]
			}
		}
	}
	return arr
}

// 二分查找
func select_list(arr []int, statr, end, number int) int {
	center := int((statr + end) / 2)
	if statr > end {
		return -1
	}
	if number > arr[center] {
		return select_list(arr, center+1, end, number)
	} else if number < arr[center] {
		return select_list(arr, statr, center-1, number)
	} else {
		return center
	}
}

func main() {
	var arr = []int{2, 10, 8, 6, 5}
	res := sort(arr)
	fmt.Println(res)

	// 二分查找
	resp := select_list(arr, 0, len(arr)-1, 6)
	fmt.Printf(">>>%v", resp)

}

golang gin clientip remoteip 区别_数组_29