go语言学习笔记4

导入包的使用
方式一:

package main

import  "fmt"
import  "os"

func main () {
	fmt.Println("this is a test")
	fmt.Println("os.Args = ", os.Args)
}

方式二:(常用)

package main

import  (
	"fmt"
	"os"
)

func main () {
	fmt.Println("this is a test")
	fmt.Println("os.Args = ", os.Args)
}
 . 操作   调用函数,无需通过包名,但容易导致重名问题
package main

import . "fmt"
import . "os"

func main () {
	Println("this is a test")
	Println("os.Args = ", Args)
}

给包取别名

package main

import io "fmt"

func main () {
	io.Println("this is a test")
}

忽略此包

package main

import _ "fmt"

func main () {
	
}

所有用go语言编译的可执行程序都必须有一个叫main的包,一个可执行程序有且仅有一个main包
package main 必须包含一个 main 函数

工程管理:同级目录
1、分文件编程(多个源文件),必须放在src目录
2、设置GOPATH环境变量
3、同一个目录,包名必须一样
4、go env 查看 go 相关的环境路径
5、同一个目录,调用别的文件的函数,直接调用即可,无需包名应用

工程管理:不同目录
1、不同目录,包名不一样
2、调用不同包里面的函数,格式:包名 . 函数名()
3、调用别的包的函数,这个包函数名字如果首字母是小写,无法让别人调用,要想别人能调用,必须首字母大写

init 函数
_ 操作
有时,用户可能需要导入一个包,但是不需要引用这个函数的标识符。在这种情况,可以使用空白标识符 _ 来重命名这个导入:

import (
	_ "fmt"
)

_ 操作其实是引入该包,而不直接使用包里面的函数,而是调用了该包里面的init函数

分类
指针计本操作
每个变量有两层含义:变量的内存,变量的地址

var a int = 10
	fmt.Printf("a = %d\n", a) //变量的内存
	fmt.Printf("a = %v\n", &a)

保存某个变量的地址,需要指针类型 *int 保存int的地址,**int 保存 *int 地址
声明(定义),定义只是特殊的声明
定义一个变量p,类型为 *int

var p *int
p = &a //指针指向谁,就把谁的地址赋值给指针变量
fmt.Printf("p = %v, &a = %v\n", p, &a)

*p = 666 //*p操作的不是p的内存,是P所指向的内存(就是a)
fmt.Printf("p = %v, &a = %v\n", p, &a)

不要操作没有合法指向的内存

package main

import "fmt"

func main () {
	var p *int
	p = nil
	fmt.Printf("p = ", p)
	
	*p = 666 //err,因为p没有合法指向
}

new函数的使用

package main

import "fmt"

func main() {
	var p *int //指向一个合法内存,p = &a
	
	p = new(int) //p是*int,指向int类型
	
	*p = 666 
	fmt.Printf("p = ", *p)
}

自动推导类型

q := new(int)
*q = 777
fmt.Printf("*q = ", *q)

go语言保留了指针,但与其他语言不同的是:
1、指针的默认值是nil,没有null常量
2、操作符 & 去变量的地址,* 通过指针访问目标对象
3、不支持指针运算,不支持 -> 运算符,直接用 . 访问目标成员

注意:不要操作没有合法指向的内存;未初始化或赋值为 nil 的指针,否则会报错
用 new()函数来生成空间用于操作内存,类似于动态分配空间,但go语言不需要考虑释放空间

普通变量做函数参数

package main

import "fmt"

func swap(a, b int) {
	a, b = b, a
	fmt.Printf("swap: a = %d, b = %d\n", a, b)
}

func main (){
	a, b := 10, 20
	//通过一个函数交换a和b的内容
	swap(a, b) //变量本身传递,值传递(站在变量角度)
	fmt.Printf("main: a = %d, b = %d\n", a, b)
}

swap: a = 20, b = 10
main: a = 10, b = 20

由于变量作用域不同,定义不同,即出现的结果:自定义函数内部变量值发生;饿变化,进行了值传递,但在住函数之中并没有交换变量的值

指针做函数参数

import "fmt"

func swap(p1, p2 int) {
	p1, p2 = p2, p1
}

func main (){
	a, b := 10, 20
	//通过一个函数交换a和b的内容
	swap(&a, &b) //地址传递
	fmt.Printf("main: a = %d, b = %d\n", a, b)
}

main: a = 20, b = 10

交换了两个变量的内存,使主函数之中实现了变量值得交换。

数组
数组是同一个类型的集合
元素必须是常量
【数字】,这个数字作为元素个数
注意:数组定义时,指定的数组元素个数必须是常量
操作数组元素,从0开始,到len()-1,不对称元素,这个数字,叫下标
下标可以是变量或常量

a[0] = 1
i := 1
a[i] = 2 //a[1] = 2
package main

import "fmt"
 func main() {
	var id [50]int
	
	//操作数组,通过下标,从零开始,到len()-1
	for i := 0; i < len(id); i++ {
		id[i] = i + 1
	fmt.Printf("id[%d] = %d\n", i, id[i])
	}
}

遍历,打印下标,返回元素`

for i := 0; i < len(a); i++ {
		a[i] = i + 1
}
for i, data := range a {
	fmt.Printf("a[&d = %d\n]", i, data)
}

数组的初始化(声明定义同时赋值,叫初始化)

1、全部初始化

var a [5]int = [5]int{1,2,3,4,5}


a = [1 2 3 4 5]

简洁写法:

a := [5]int{1,2,3,4,5}


a = [1 2 3 4 5]

2、部分初始化,没有初始化的元素,自动复制为0

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


a = [1 2 3 0 0]

指定某个元素初始化

a := [5]int{2: 10, 4: 20}
fmt.Println("a = ", a)
	
	
a = [0 0 10 0 20]

有多少个[]就是多少维
有多少个[]就用多少个循环
二维数组

var a [3][4]int
	
	k := 0
	for i := 0; i < 3; i++{
		for j := 0; j < 4; j++{
			k++
			a[i][j] = k
			fmt.Printf("a[%d][%d] = %d, ", i, j, a[i][j])
		}
		fmt.Printf("\n")
	}
	fmt.Println("a = ", a)

有3个元素,每个元素又是一维数组[4]int

a := [3][4]int{{1,2,3,4},{5,6,7,8},{9,10,11,12}}

数组的比较和赋值:
比较只能用==或者!=,返回布尔变量
只能比较同样的数组类型是不是每个元素都一样
同类型的数组可以赋值

随机数的使用
设置种子,只需一次

rand.Seed(123)

产生随机数

fmt.Println(rand.Int())

如果种子参数一样,每次运行程序产生的随机数都一样

package main

import "fmt"
import "math/rand"
import "time"

func mian(){
    rand.Seed(time.Now().UnixNano()) //以当前系统时间作为种子参数
    
    for i := 0; i < 5 ; i++{
    	fmt.Println("rand = ", rand.Intn(100)) //限制在100内的数
    }
}

冒泡排序
挨着两个元素比较
升序,大于交换

package main
 
import "fmt"
import "math/rand"
import "time"
 
func main() {
	rand.Seed(time.Now().UnixNano()) //设置时间种子
	
	var a [10]int
	n := len(a)
	
	for i := 0; i < n; i++ {
		a[i] = rand.Intn(100) //生成100以内随机数
		fmt.Printf("%d,", a[i])
	}
	fmt.Println("\n")
	//冒泡排序,相邻两元素比较排序,升序,大则交换
	for i := 0; i < n-1; i++ {
		for j := 0; j < n-1-i; j++ {
			if a[j] > a[j+1] {
				a[j], a[j+1] = a[j+1], a[j]
			}
		}
	}
	fmt.Println("\n排序完成:\n"){
		for i :=0; i < n; i++ {
			fmt.Printf("%d, ", a[i])
	}
	fmt.Printf("\n")
}

数组做函数参数
数组做函数参数,它是值传递
实参数组的每一个元素给形参数组拷贝一份
形参的数组是实参数组的复制品

package main

import "fmt"

func modify(a [5]int){ 
    a[0]=10
    fmt.Println("modify a = ", a)
}

func main(){
    a := [5]int{1,2,3,4,5} //初始化
    
    modify(a)
    fmt.Println("main a = ", a)
}

数组指针做函数参数
p指向实现数组a,它是指向数组,它是数组指针
*p代表指针所指向的内存,就是实参a

package main

import "fmt"

func modify(p *[5]int){
    (*p)[0]=10
    fmt.Println("modify a = ", *p)
}

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

数组的大小是固定的,在参数传递时必须完整传递,故引入切片的概念和功能来弥补数组的缺点。同时切片也可以理解为变长的动态数组。切片不指定长度,从数组切入。
low:切片下标的起点

high:切片下标的终点(不包括)

切片的长度len=high-low

切片的容量cap=max-low

切片的初始化

a := []int{1,2,3,0,0}    //中括号内可以省略...

切片和数组的区别:
1、数组[]长度是固定的一个常量,不能修改长度,长度和容量都是那个常量。
2、切片,[]里面为空或…,切片的长度和容量可以不固定。
3、append(s,11) 可为切片s末尾追加元素11。

切片的创建:
自动推导类型

s1 := []int{1,2,3,4}

借助make函数,格式make(切片类型,长度,容量)

s2 := make([]int, 5, 10)

没有指定容量,容量和长度

s3 := make([]int, 5)

切片的截取

package main

import "fmt"

func main() {
	array:=[]int{1,2,3,4,5,6,7,8,9}
	//[low:high:max]取下标从low开始的元素,len=high-low, cap=max-low
	s1 :=array[:]    //[0:len(array):len(array)]不指定容量和长度一样
	fmt.Println("s1 = ", s1)
	fmt.Printf("len = %d, cap = %d\n", len(s1), cap(s1))
	
	//操作某个元素,和数组操作方式一样
	data := array[1]
	fmt.Println("data = ", data)
	
    s2 :=array[3:6:7]    //a[3], a[4],a[5] len = 6-3=3   cap = 7-3=4
    fmt.Println("s2 = ", s2)
    fmt.Printf("len = %d, cap = %d\n", len(s2), cap(s2))
    
    s3 :=array[:6]    //从0开始取6个元素,长度和容量都是6,此方法最为常用
    fmt.Println("s3 = ", s3)
    fmt.Printf("len = %d, cap = %d\n", len(s3), cap(s3))
    
    s4 :=array[3:]    //从array[3]开始,取到结尾
   
}

切片和底层数组关系

package main

import "fmt"

func main(){
	a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	//新切片
	s1 := a[2:5] //从a[2]开始,取3个元素
	fmt.Peintln("s1 = ", s1)
	
	//另外新切片
	s2 := s1[2:7]
	s2[2] = 777
	fmt.Println("s2 = ", s2)
	fmt.Println("a = ", a)
}

注意:切片指向底层数组,在对某个切片元素重新赋值时,无论切片经过多少次重切,切片所指向的最底层数组的相应元素也会跟着被重新赋值,改变

append函数的使用

package main

import "fmt"

func mian(){
	s1 := []int{}
	fmt.Printf("len = %d, cap = %d\n", len(s1), cap(s1))
	fmt.Println("s1 = ", s1)
	
	//在原切片的末尾添加元素
	s1 = append(s1, 1)
	s1 = append(s1, 2)
	s1 = append(s1, 3)
	fmt.Printf("len = %d, cap = %d\n", len(s1), cap(s1))
	fmt.Println("s1 = ", s1)
	
	s2 := []int{1, 2, 3}
	fmt.Println("s2 = ", s2)
	s2 = append(s2, 5)
	s2 = append(s2, 5)
	s2 = append(s2, 5)
	fmt.Println("s2 = ", s2)
}

append扩容特点
如果超过原来的容量,通常以2倍容量扩容

package main

import "fmt"

func mian(){
	s := make([]int, 0, 1) //容量为1
	oldCap := cap(s)
	for i := 0;i < 20; i++{
		s = append(s, i)
		if newCap := cap(s); oldCap < newCap {
			fmt.Printf("cap: %d ===> &d\n", oldCap, newCap)
			
			oldCap = newCap
		}
	}
}

copy的使用

package main

import "fmt"

func mian(){
	srcSlice := []int{1, 2}
	dstSlice := []int{6, 6, 6, 6, 6}
	
	copy(dstSlice, srcSlice)
	fmt.Println("dst = ", dstSlice)
}

切片做函数参数
引用传递,传递方式与数组值传递相同,但不会完整传递,只会传递所需的某个元素

package main

import "fmt"
import "math/rand"
import "time"


func InitData(s []int) {
	//设置种子
	rand.Seed(time.Now().UnixNano()) 
	
	for i := 0; i < len(s); i++ {
		s[i] = rand.Intn(100) //生成100以内随机数
	}
}
//冒泡排序
func BubbleSort(s []int){
	n := len(s)
	
	for i := 0; i < n-1; i++{
		for j := 0; j < n-1-i; j++{
			if s[j] > s[j+1]{
				s[j], s[j+1] = s[j+1], s[j]
			}
		}
	}
}

func mian(){
    n := 10
	
	//创建一个切片,len为n
	s := make([]int, n)
	
	InitData(s)  //初始化数组
	fmt.Println("排序前:", s)
	
	BubbleSort(s)  //冒泡排序
	fmt.Println("排序后:", s)
}

一个4位数取出每一位数

func GetNum(s []int, num int){
	s[0] = num / 1000       //取千位
	s[1] = num % 1000 / 100 //取百位
	s[2] = num % 100 / 10   //取十位
	s[3] = num % 10         //取个位
}

map的介绍
map(映射、字典)是一种内置的数据结构,它是一个无序的key-value对的集合
map格式:map[key类型]value类型{}
在一个map里所有的键都是唯一的,而且必须是支持==和!=操作符的类型,切片、函数以及包含切片的结构类型这些类型由于具有引用语义,不能作为映射的键,使用这些类型会造成编译错误

map的基本使用

package main

import "fmt"

func main(){
	//定义一个变量,类型为map[int]string
	var m1 map[int]string
	fmt.Println("m1 = ", m1)
	//对于map只有len,没有cap
	fmt.Println("len = ", len(m1))
	
	//可以通过make创建
	m2 := make(map[int]string)
	fmt.Println("m2 = ", m2)
	fmt.Println("len = ", len(m2))
	
	//可以通过make创建,可以指定长度,只有指定了容量, 但是里面却是一个数据也没有
	m3 := make(map[int]string, 2)
	m3[1] = "mike"  //元素的操作
	m3[2] = "go"
	m3[3] = "c++"

    fmt.Println("m3 = ", m3)
	fmt.Println("len = ", len(m3))
}

键值是唯一的

m4 := map[int]string{1:"mike", 2:"go", 3:"c++"}
fmt.Println("m4 = ", m4)

map的赋值:
赋值,如果已经存在的key值,修改内容

m[1]=”c++”   
m[3]=”go”    //追加,map底层自动扩容,和append类似

map的遍历:
第一个返回值为key,第二个返回值为value,遍历结果是无序的

for key,value:=range m{} 

判断key是否存在:
第一个返回值为key所对应的value,第二个返回值为key是否存在的条件,存在ok为true

value, ok :=m[0]     
    if ok == true {
	    fmt.Println("m[1] = ", value)
    }else{
	fmt.Println("key不存在")
    }
}

map删除

delete(m,1)    //删除key为1的内容

map做函数参数

package main

import "fmt"

func test(m map[int]string){
	delete(m, 1)
}

func main(){
	m := map[int]string{1:"map", 2:"yo", 3:"go"}
	fmt.Println("m = ", m)
	
	test(m) //在函数内部删除某个key
	
	fmt.Println("m = ", m)
}

结构体类型
结构体普通变量初始化

package main

import "fmt"

//定义一个结构体类型
type Student struct{
    id int
    name string
    sex byte   //字符类型
    age int
    addr string
}

func main(){
	//顺序初始化,每个成员必须初始化
	var s1 Student = Student{1,"mike",'m',18,"bj"}
	fmt.Println("s1 = ", s1)
	
	//指定成员初始化,没有初始化的成员自动复制为0
	s2 := Student{name:"mike", addr: "bj"}  
	fmt.Println("s2 = ", s2)
}


结构体指针变量初始化

func main(){
	//顺序初始化,每个成员必须初始化,别忘了&
	var p1 *Student = &Student{1,"mike",'m',18,"bj"}
	fmt.Println("p1 = ", p1)
	
	//指定成员初始化,没有初始化的成员自动复制为0
	p22 := Student{name:"mike", addr: "bj"}  
	fmt.Println("p2 type is %T\n", p2)
	fmt.Println("p2 = ", p2)
}

结构体成员的使用:普通变量

func main(){
	//定义一个结构体普通变量
	var s Student
	
	//操作成员,需要使用点(.)运算符
	s.id = 1
	s.name = "mike"
	s.sex = "m"
	s.addr = "bj"
	fmt.Println("s = ", s)
}

结构体成员的使用:指针变量
1、指针有合法指向后,才操作成员

func main(){
	//定义一个结构体普通变量
	var s Student
	//定义一个指针变量,保存s的地址
	var p1 *Student
	p1 = &s
	
	//通过指针操作成员 p1.id 和(*p1).id完全等价,只能使用.运算符
	p1.id = 1
	(*p1).name = "mike"
	p1.sex = "m"
	p1.addr = "bj"
	fmt.Println("p1 = ", p1)
}

2、通过new申请一个结构体

    p2 := new(Student)
	p2.id = 1
	p2.name = "mike"
	p2.sex = "m"
	p2.addr = "bj"
	fmt.Println("p2 = ", p2)

结构体比较和赋值
与数组比较相类似,只能用==和!=运算符,返回布尔类型
同类型的结构体可以相互赋值

结构体作为函数参数:值传递

package main

import "fmt"

//定义一个结构体类型
type Student struct{
    id int
    name string
    sex byte   //字符类型
    age int
    addr string
}
func test(s Student){
	s.id = 123
	fmt.Println("test: ", s)
}

func main(){
	s := Student{1, "mike", 'm', 18, "bj"}
	
	test (s)  //值传递,形参无法改实参
	fmt.Println("main: ", s)
}

结构体作为函数参数:地址传递/引用传递

package main

import "fmt"

//定义一个结构体类型
type Student struct{
    id int
    name string
    sex byte   //字符类型
    age int
    addr string
}
func test(p *Student){
	p.id = 123
}

func main(){
	s := Student{1, "mike", 'm', 18, "bj"}
	
	test (&s)  //地址传递,形参无法改实参
	fmt.Println("main: ", s)
}

go语言可见性
如果想使用其他包的函数、结构体类型、结构体成员、函数名、类型名,结构体成员变量名的首字母必须大写。如果首字母是小写,则只能在同一个包里面使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值