package main
import (
"fmt"
"unicode/utf8"
)
//全局变量
var (
a1 int
b1 bool
)
//声明结构体
type Books struct {
title string
author string
}
func getDate() (int, int) {
return 10, 20
}
func main() {
fmt.Println("============初识go语言============")
fmt.Println("hello, go!")
fmt.Println("============定义变量(指定类型未初始化 默认0,false,空字符串值)============")
var a int = 100
fmt.Println(a)
var b int
fmt.Println(b)
var c bool
fmt.Println(c)
var d string
fmt.Println(d)
fmt.Println("============多变量声明============")
//:= 含义--> typename := value 等同于 1.var typename 类型 ;2.typename = value;
var x, y int
var c1, d1 int = 1, 2
g1, h1, e1 := 123, "hello", true
fmt.Println(x, y, c1, d1, g1, h1, e1)
fmt.Println("============全局变量的声明============")
fmt.Println(a1)
fmt.Println(b1)
fmt.Println("============匿名变量============")
//使用匿名变量时,只需要在变量声明的地方使用下画线替换即可。
//任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用
a2, _ := getDate()
_, b2 := getDate()
fmt.Println(a2)
fmt.Println(b2)
fmt.Println("============指针声明和初始化============")
//指向整型
var ip *int
//指向浮点型
var fp *float32
var a3 int = 20
//指针变量的存储地址
ip = &a
fmt.Println(fp) // <nil> 空指针
fmt.Println(a3) // 20
fmt.Println(ip) // 0xc00000e118
fmt.Println("============声明数组============")
//一维数组
var balance [10] float32
fmt.Println(balance) // [0 0 0 0 0 0 0 0 0 0]
//1.直接进行初始化
var balance1 = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
fmt.Println(balance1)
//2.快速初始化
balance2 := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
fmt.Println(balance2)
//3.通过元素个数自行推断数组长度
balance3 :=[...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
fmt.Println(balance3)
//4.数组长度确定,指定下标进行部分初始化
balance4 :=[5]float32{1:2.0,3:7.0}
fmt.Println(balance4) //[0 2 0 7 0]
fmt.Println("============数组指针============")
var A = [...]int{1,2,3} // 数组A
var B = &A //B是指向数组A的指针
q := &A //q是指向数组A的指针
fmt.Println(B[2]) //3
fmt.Println(q[2]) //3
fmt.Println("============for range遍历数组============")
for i, v := range B { // 通过数组指针迭代数组的元素
fmt.Println(i, v)
}
fmt.Println("============结构体变量============")
var book Books
book.title = "fade.luo"
book.author = "Go语言入门"
fmt.Println(book)
fmt.Println("============结构体指针============")
var po *Books //po 是 Books类型的指针
po = &book // 指向book
fmt.Println(po)
fmt.Println(po.title,po.author)
fmt.Println("============字符串定义和初始化============")
//go 字符串底层结构就是个结构体,由字节数组和字节长度组成
//Tip:utf-8下一个汉字等于三个字符,所以汉字字符串的长度为5*3。
str1 :="我是太阳妈"
str2 :="I am the sun mom"
fmt.Println(len(str1),len(str2)) //15 16
fmt.Println("============转义字符============")
//使用"`"字符 定义不做转义的原始字符串(原样输出),支持跨行。
str3 :=`line\r\n,
line2`
fmt.Println(str3)
fmt.Println("============遍历字符串============")
str4 := "我是心源流败门子"
//1.byte方式 遍历原始的字节码--输出3*8 24个字节
for i:=0;i<len(str4);i++ {
fmt.Printf("%d:[%c]\n",i,str4[i])
}
//2.rune方式 遍历字节数组--0:[我]3:[是]6:[心]9:[源]12:[流]15:[败]18:[门]21:[子]
for i,c:=range str4{
fmt.Printf("%d:[%c]\n",i,c)
}
fmt.Println("============获取字符串长度============")
//当字符串时单字节时,可以使用len()函数获取;当为多字节时,可以使用 utf8 中的 RuneCountInString获取字符串长度,也可以将字符串转换为rune切片,然后通过 len 函数获取长度。
str5 :="中国"
fmt.Println(utf8.RuneCountInString(str5))
runes :=[]rune(str5)
fmt.Println(len(runes))
fmt.Println("============array是同类型元素的数组。array在声明的时候会指定长度且不能改变。============")
var array [5] int
fmt.Println(array)
fmt.Println("============创建Slices 是能随时扩容的同类型元素的序列============")
//slice结构定义
/* type SliceHeader struct {
Data uintptr // 指向底层的的数组指针
Len int // 切片长度
Cap int // 切片最大长度
}*/
slice := []int{1, 2, 3, 4}
fmt.Println(slice) //[1 2 3 4]
fmt.Println("============创建子slice1============")
slice1 := slice[2:]
fmt.Println(slice1) //[3 4]
fmt.Println("============创建子slice2============")
slice2 := slice[:2] //[1 2]
fmt.Println(slice2)
fmt.Println("============添加元素============")
//append() :内置的泛型函数,可以向切片中增加元素。
//1.在切片尾部追加N个元素
var s1 []int
s1 = append(s1,1) //追加一个元素
fmt.Println(s1) //[1]
s1 = append(s1,1,2,3) //追加多个元素
fmt.Println(s1) // [1 1 2 3]
s1 = append(s1,[]int{1,2,3}...) //追加一个切片, 切片需要解包
fmt.Println(s1) //[1 1 2 3 1 2 3]
//2.在切片开头位置添加元素
var s2 = []int{1,2,3}
fmt.Println(s2) //[1 2 3]
s2 = append([]int{0}, s2...) // 在开头位置添加1个元素
fmt.Println(s2) //[0 1 2 3]
s2 = append([]int{-3,-2,-1}, s2...) // 在开头添加1个切片
fmt.Println(s2) //[-3 -2 -1 0 1 2 3]
//Tip:在开头一般都会导致内存的重新分配,而且会导致已有的元素全部复制1次。因此,从切片的开头添加元素的性能一般要比从尾部追加元素的性能差很多。
//3.append链式操作
var s3 = []int{1,2,3,4,5}
s3 = append(s3[:2],append([]int{99},s3[2:]...)...) //在2号位之前的子数组后面加,在2号位后面的子数组前面加 99
fmt.Println(s3) //[1 2 99 3 4 5]
var s4 = []int{1,2,3,4,5}
s4 = append(s4[:2], append([]int{9,9,9}, s4[2:]...)...) // 在第i个位置插入切片
fmt.Println(s4) //[1 2 9 9 9 3 4 5]
//4.append和copy组合
s5 := []int{1,2,3}
s5 = append(s5,0) //[1 2 3 0]
copy(s5[2:],s5[1:]) //2 3 0往后移动一格-->将s5[1:](2 3 0)的内容复制到s5[2:](3 0)切片中 -->s5[2:](2 3)
fmt.Println(s5) //[1 2 2 3]
s5[1] = 9
fmt.Println(s5) //[1 9 2 3]
fmt.Println("============删除元素============")
//1.从开头位置删除
//直接通过移动指针,来删除数据
q1 :=[]int{1,2,3}
fmt.Println(q1) //[1 2 3]
q1 = q1[1:]
fmt.Println(q1) //[2 3]
//2.从中间位置删除 需要对剩余的元素进行一次整体挪动,可以用append或copy原地完成
q2 :=[]int{1,2,3,4,5}
fmt.Println(q2) //[1 2 3 4 5]
q2 = append(q2[:1],q2[2])
fmt.Println(q2) //[1 3]
q3 :=[]int{1,2,3,4,5}
q3 = append(q3[:1],q3[2:]...)
fmt.Println(q3) //[1 3 4 5]
// 删除中间一个
q4 :=[]int{1,2,3,4,5}
q4 = q4[:copy(q4[:1],q4[2:])] //q4[:1]-> 1 q4[2:]->3 4 5 复制源切片大于复制目标切片->只会复制前一个元素到q4[:1]中
fmt.Println(q4) //[3]
// 删除中间n个 ???
q5 :=[]int{1,2,3,4,5}
q5 = q5[:copy(q5[:1],q5[1+3:])]
fmt.Println(q5) //[5]
//3.从尾部删除
q6 :=[]int{1,2,3,4,5}
// 删除尾部1个元素
q6 = q6[:len(q6)-1]
fmt.Println(q6)
// 删除尾部3个元素
q7 :=[]int{1,2,3,4,5}
q7 = q7[:len(q7)-3]
fmt.Println(q7)
fmt.Println("============函数============")
//可以将函数保持到变量中,有具名和匿名之分
//包级函数一般都是具名函数,具名函数是匿名函数的一种特例,当匿名函数引用了外部作用域中的变量时就成了闭包函数
/**
闭包函数:返回为函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。
一级对象:支持闭包的多数语言都将函数作为第一级对象,就是说函数可以存储到变量中作为参数传递给其他函数,最重要的是能够被函数动态创建和返回。
包:go的每一个文件都是属于一个包的,也就是说go是以包的形式来管理文件和项目目录结构的。
*/
fmt.Println("============具名函数============")
//具名函数:就和c语言中的普通函数意义相同,具有函数名、返回值以及函数参数的函数。
fmt.Println(Add(15,5,))
fmt.Println("============匿名函数============")
//匿名函数:指不需要定义函数名的一种函数实现方式,它由一个不带函数名的函数声明和函数体组成。
var Add2 = func(a,b int) int{ return a+b}
fmt.Println(Add2(5,5,))
fmt.Println("============函数声明和定义============")
/**
func fuction_name([parameter list])[return types]{
函数体
}
*/
fmt.Println("============函数传参============")
/**
Go语言中的函数可以有多个参数和多个返回值,参数和返回值都是以传值的方式和被调用者交换数据。
在语法上,函数还支持可变数量的参数,可变数量的参数必须是最后出现的参数,可变数量的参数其实是一个切片类型的参数。
*/
var h2 = []int{1, 2, 3}
Print(1,2) // 解包 1 2
Print(h2) // 未解包 [1 2 3]
fmt.Println("============函数返回值============")
/**
不仅函数的参数可以有名字,也可以给函数的返回值命名。
*/
}
// 具名函数
func Add(a, b int) int {
return a+b
}
func Print(h2 ...interface{}) {
fmt.Println(h2...)
}
控制台:
============初识go语言============
hello, go!
============定义变量(指定类型未初始化 默认0,false,空字符串值)============
100
0
false
============多变量声明============
0 0 1 2 123 hello true
============全局变量的声明============
0
false
============匿名变量============
10
20
============指针声明和初始化============
<nil>
20
0xc0000a6058
============声明数组============
[0 0 0 0 0 0 0 0 0 0]
[1000 2 3.4 7 50]
[1000 2 3.4 7 50]
[1000 2 3.4 7 50]
[0 2 0 7 0]
============数组指针============
3
3
============for range遍历数组============
0 1
1 2
2 3
============结构体变量============
{fade.luo Go语言入门}
============结构体指针============
&{fade.luo Go语言入门}
fade.luo Go语言入门
============字符串定义和初始化============
15 16
============转义字符============
line\r\n,
line2
============遍历字符串============
0:[æ]
1:[]
2:[]
3:[æ]
4:[]
5:[¯]
6:[å]
7:[¿]
8:[]
9:[æ]
10:[º]
11:[]
12:[æ]
13:[µ]
14:[]
15:[è]
16:[´]
17:[¥]
18:[é]
19:[]
20:[¨]
21:[å]
22:[]
23:[]
0:[我]
3:[是]
6:[心]
9:[源]
12:[流]
15:[败]
18:[门]
21:[子]
============获取字符串长度============
2
2
============array是同类型元素的数组。array在声明的时候会指定长度且不能改变。============
[0 0 0 0 0]
============创建Slices 是能随时扩容的同类型元素的序列============
[1 2 3 4]
============创建子slice1============
[3 4]
============创建子slice2============
[1 2]
============添加元素============
[1]
[1 1 2 3]
[1 1 2 3 1 2 3]
[1 2 3]
[0 1 2 3]
[-3 -2 -1 0 1 2 3]
[1 2 99 3 4 5]
[1 2 9 9 9 3 4 5]
[1 2 2 3]
[1 9 2 3]
============删除元素============
[1 2 3]
[2 3]
[1 2 3 4 5]
[1 3]
[1 3 4 5]
[3]
[5]
[1 2 3 4]
[1 2]
============函数============
============具名函数============
20
============匿名函数============
10
============函数声明和定义============
============函数传参============
1 2
[1 2 3]
============函数返回值============
Process finished with exit code 0