go 语言基础

本文详细介绍了Go语言的基础知识,包括变量的声明与类型(如整数、浮点数、字符和布尔类型)、指针、数据类型转换、流程控制(if、switch、for)以及函数的使用。特别强调了Go语言中的变量作用域、指针修改值的特性,还探讨了字符串处理、错误处理和包的管理。此外,文章还涉及到了Python与Go语言在参数传递上的差异。
摘要由CSDN通过智能技术生成

结构

go mod init xx 初始化文件

编译: go build xx.go 生成.exe文件

go run xx.go 执行文件

image-20210602222152060


文件结构

filename|

​ —src 文件代码

1.变量

声明

var age =12  //声明变量

var age  int  //指定变量类型 不赋值  默认为0

age :=12  //如果不写变量的类型,根据后面的数据类型判断定义的类型

// 多变量声明
var num1 ,num2 int

n1,n2 :=2,3

//一次声明多个变量
var (
		n1 = 12
		n2 = 2
		n3 = 12
	)


fmt.Printf("%T",n1)  //输出变量类型


变量类型:

image-20210606141004408

整数类型:

byte =uint 8 范围 0-256

image-20210606180518349

image-20210606180539325

image-20210606180556017

负数二进制表示: 补码表示:即反码+1

-5 计算机中表示 0000 0101 反码 111 1010 -> 补码 1111 1011,

int8 范围 1000 0000 -1 = 反码 01111 1111 -> 初始 1000 0000 -> 即-128 — 127 范围

输出变量类型
package main
// 导入多包操作
import(
	"fmt"
	"unsafe"
)

func  main()  {
	var n1 int
	
	fmt.Printf("%T",n1)  //输出变量类型
	fmt.Println(unsafe.Sizeof(n1))  //输出变量占用字节数 ->8

}

浮点数:

可能会有精度的丢失> 建议使用float64

image-20210606180456487

默认使用float 64

image-20210606201819805

字符类型

var a byte = ‘a’

fmt.println(a) //输出67 ASCII 码值

goloang 的字符对应的使用的是UTF-8的编码(unicode 是对应的字符串,UTF-8是Unicode的其中一种编码方案)

func  main()  {
	var n1 byte ='a'
	fmt.Println(n1)  //输出对应的ASCII值
	fmt.Printf("%c",n1)   // 输出a字符
}

转义字符: \开头

image-20210606203245000

布尔类型

bool 类型只允许true 和 false 默认声明未定义时 值为 false

var f bool

字符串类型

字符串是不可变的,指的是字符串一旦定义好,其中的字符的值不能改变

var s1 string ="abc"
s1="nnn"  //可以修改
s1[0]="n"   //错误


如果字符串中有特殊字符, 使用反引号
var s2 string = `nihao "dea" `
字符拼接
var s3 string = "ABC" + "abc"

换行
var s4 string = "123" +
				"234"   //go 或默认添加换行 ,因此将 + 号放到上行最后 代表语句未执行结束 
				

数据类型转换

表达式 T(v) T 目标类型 v 需要转换的变量

func  main()  {
	var n1 int =100
	var n2 float32 = float32(n1)  //注意: n1 的类型还是 int 类型 ,只是将n1 的值100 转成float32
	
	fmt.Println(n2)
	fmt.Printf("n1:%T\n",n1)    // int
	fmt.Printf("n2:%T",n2)         // float32
	将int 64 转成 int 8  会导致数据的溢出
	var n3 int64 = 88888
	var n4 int8 = int8(n3)
	
}

基本数据类型(整数,浮点等)转string 类型

方式1:
fmt.Sprintf()

func  main()  {
	var n1 int =100
	var s1 string = fmt.Sprintf("%d",n1)   //%d 源数据类型
	fmt.Printf("s1 tytpe %T ,value %s",s1,s1)
}

方式2: strconv  中FormatXXX方法

package main

import (
	"fmt"
	"strconv"
)

func  main()  {
	var n1 int =100
	var s1 string = strconv.FormatInt(int64(n1),10)   //第一个参数必须为 int 64 第二个参数指定值的进制形式 10位10进制形式
	fmt.Printf("s1 tytpe %T ,value %s",s1,s1)
}


string -> 其他类型 strcon.ParseXXX string 转其他数据类型,一定要确保能够转换,否则最后的到的结果就是 对应数据类型的默认值

package main

import (
	"fmt"
	"strconv"
)

func main() {
	var n1 string = "123"
	var s1,_ = strconv.ParseInt(n1,10 ,8)  //返回2个值 第二个值 用_ 省略
	fmt.Printf("s1 tytpe %T ,value %v", s1, s1)
}

指针

  • &+变量 获取变量 内存中的地址

  • 指针变量:

    • 定义一个变量 var 指针变量名称 指针类型

      • ​ var par * int =&age
      package main
      
      import (
         "fmt"
      )
      
      func main() {
         var n1 string = "123"
         var ptr *string =&n1
         fmt.Println(ptr)   //0xc000038240
      
         fmt.Println(&ptr)  //  0xc000006028
         fmt.Println(*ptr)   //123
      }
      
指针

总结最重要的两个符号 & (取内存地址 ) *(取内存地址对应的值)

指针修改值
func main() {
   var n =10
   var ptr * int =&n
   *ptr =12
   fmt.Println(n)    //12
}

标志符

即变量 : 数字、字符 、 下划线   。 严格区分大小写 、首字母不能为数字、不能包含空格、不可以使用关键字

​ — 下划线 起到忽略作用

import ("fmt"
   _"strconv"
)

起名规则

  1. 包名: package 的名称建议和目录一致

  2. main 包是一个程序的入口包,所以main函数他所在的包 定义为package main ,如果不定义成main包,那么就不能得到可执行文件

  3. 首字母大写, 则可以被其他包访问 (包名是在GOROOT下放置)

    配置GOPATH

    拍错

    image-20210607211600092

image-20210607211632148

go env -w GO111MODULE=off

image-20210607212136564

方法2

go env -w GO111MODULE=on

go mod init goFIles 生成go.mod 文件

包名是从$GOPATH/src/ 后开始计算的

image-20210607213523378

运算符

package main

import (
	"fmt"
	_ "goFiles/src/test"
)

func main() {
	var n1 int8 = 10
	var n2 int8 = 12
	var sum int8 = n1+n2
	fmt.Println(sum)
	var  c  int8= n1*n2
	fmt.Println(c)
	var m int8 = n2%n1   //取模 取余
	fmt.Println(m)

}
 

获取用户输入

package main

import (
   "fmt"
)

func main() {
   var age int

   fmt.Println("请输入age:")
   
   fmt.Scanln(&age)  

   fmt.Println(age)

}

流程控制

分支结构

if
if 条件表达式{
	逻辑代码
}else if 条件表达式{       // else 前必须在}后间 
	 逻辑代码
}else{
	逻辑代码
}


switch
switch 表达式有返回值{
	case key1,key1.1,key1.2 :   //case 后可以接多个值用 逗号隔开
		表达式
	case key2:
		表达式
	default:
		以上条件都不满足的时候,才运行
	
}
for
for i:=0 ; i <5; i++{
	循环体
}
注意 for的 初始表达式不能使用var 定义变量的形式


方式2
i:=1
for i<10{
	i++
}

for range 结构
for key,val range dict{

}

模拟while
var x int = 0
	for x < 5 {
		fmt.Println(x)
		x++
	}
for range
x:=[3]int{1,2,3}

x := [3]int{1, 2, 3}
	for i,j :=range x{
		fmt.Println(i,j)
	}

break 只能结束最近的一层循环

结束指定标签对应的循环
func main() {

	lable1:   //标记第一个for循环打上标签
	for i := 0; i < 10; i++ {
		fmt.Println(i)
		for j := 0; j < 10; j++ {
			if j == 1 {
				break lable1  //跳出第一层循环
			}
		}

	}
}

goto 跳转到程序到指定的行
代码
goto label1
代码
lable1:
代码
return
func 函数(形参)(返回值类型列表){
	return 返回值
}

函数

首字母大写相当于Public  可以被本包文件和其他包文件使用 
首字母小写 相当于private  只能被本包使用
func main() {
   n1 := 1
   n2 := 2
   r1,r2 := calc(n1,n2)
   
   fmt.Println(calc(n1, n2))
}
func calc(num1 int, num2 int) (int,int) {  //如果返回一个参数的话, 可以省略()
   return num1+num2 ,num1-num2

}

python 中参数内存处理

函数运行1

Python中参数的传递都是“引用传递”,具体分两类:

对“可变对象”进行“写操作”,直接作用于原对象本身。
对“不可变对象”进行“写操作”,会产生一个新的“对象空间”,并用新的值填充这块空间。(起到其他语言的“值传递”效果,但不是“值传递”)
可变对象:字典、列表、集合、自定义对象
不可变对象:数字、元组、字符串、function等

def l(a, b):
    print("a_id:{},b_id:{}".format(id(a), id(b)))
    a = 10
    print("a_id:",id(a))
    b[1] = 20
    print("b_id",id(b))


a = 0
b = [0, 0]
print("a_id:{},b_id:{}".format(id(a), id(b)))

l(a, b)
print(a, b)

输出:
a_id:140730996810544,	b_id:1879277392584
a_id:140730996810544,	b_id:1879277392584
a_id: 140730996810864
b_id 1879277392584
0 [0, 20]

参考连接1

参考链接2

go 语言

实参传递形参会拷贝,修改形参时不会影响实参 , go 不同于python,可变类型也会被复制,修改形参不影响实际参数

image-20210609221057299

func main() {
    var a int=0
    var b int =1
   	c:=[3]int{0,0,0}
    fmt.Println(&a,&b,&c)    //88  a0 [0,0,0]
    l(a,b,c)
    fmt.Println(a,b,c)         // 输出0,1 [0,0,0]
   }
  func l(a int ,b int,c [3]int){
  	fmt.Println(a,b,c)
  	fmt.Println(&a,&b,&c)  //e0  e8 [0,0,0]  已经被复制
  	a=12
  	b=12
  	c[0]=12            //修改形参中可变对象的值
  	fmt.Println(&a,&b,&c)

 
  }

image-20210610132520005

修改实参值
func main() {
   n1 := 1
   n2 := 2
   swap(&n1, &n2)
   fmt.Println(n1,n2)  //交换n1 和 n2  -> 2 ,1
}
//参数类型为指针
func swap(num1 *int, num2 *int) { //如果返回一个参数的话, 可以省略()
   var t int
   t=*num1
   *num1=*num2
   *num2=t
   //方式2
	*num1, *num2 = *num2, *num1

}

函数不支持重载 (函数名相同 java)

可变参数   ... 来表示

func main() {
	n1 := 1
	n2 := 2
	swap(n1, n2)
	fmt.Println(n1,n2)  //交换n1 和 n2  -> 2 ,1
}
        // 参数名 ... 类型
func swap(t...int) { //如果返回一个参数的话, 可以省略()
	fmt.Println(t)   // 输出[1,2]
	for i:=range t{
		fmt.Println(i)
	
}

go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量了. 可以通过该变量对函数进行调用(类似别名)

func main() {
	n1 := 1
	n2 := 2
	//函数也是一种数据类型,可以赋值给变量
	sw:=swap    //变量就是一个函数类型的变量
	//等价于对函数进行调用
	sw(n1, n2)
	fmt.Println(n1,n2) 
}
func swap(t...int) { //如果返回一个参数的话, 可以省略()
	fmt.Println(t)
	for i:=range t{
		fmt.Println(i)

	}

函数也是数据类型,函数也可以作为形参

func main() {
   //t:=test
   test2(test)
}
func test(t ...int) { //如果返回一个参数的话, 可以省略()
   fmt.Println("test")

}

func test2(fun func(...int)) {
   fmt.Println("test2")
   fun(1) // 传入函数
}

支持自定义类型,相当于取别名 虽然是别名,但是go在编译中识别认为 myint 和int 不是同一种数据类型,支持函数type别名

type 别名 数据类型

type myint int

func main() {
	type myint int
	var a int = 10
	var b myint
	
	b = myint(a)   //int -> myint
	fmt.Println(b)
}

type绝不只是用于定义一系列的别名。还可以针对新类型定义方法。
上面的name类型可以像下面这样定义方法:

type name string
func (n name) len() int {
	return len(n)
}
func main() {
	var myname name = "taozs" //其实就是字符串类型
	l := []byte(myname)  //字符串转字节数组
	fmt.Println(len(l))  //字节长度
	
	fmt.Println(myname.len()) //调用对象的方法
}

type 定义函数

func main() {
	var i int =0
	var j int =1

	add_d(add,i,j)

   }

 type add1 func (a int,b int)   //定义传入两个int型的函数变量

 func add(a int,b int) {
 	fmt.Println(a,b)
 	
 }
 func add_d(fu add1,a int,b int) {  //声明fu用于接收函数变量
 	fu(a,b)                    //电泳传入函数
 	fmt.Println("---")
 	
 }

支持函数返回值命名,

func test(t int) (sun int,sub int){ 
   sun:=t+1
   sub:=t-1
   return
   }

包的引入

项目根目录下 使用go mod init 项目根目录文件名 生成x.mod文件

image-20210610211705470

image-20210610211739207

image-20210610211836834

goFiles|
	   |_src
	     |_test
	   	   |_test.go
	   	 |_main.py

//main.go
package main

import (
	"fmt"
	"goFiles/src/test"  //包路径
)

func main() {
	//t:=test
	fmt.Println(1)
	fmt.Println(test.TestNum)  //使用是前面要定位到所在包  test(包名).TestNUm
}

//test.go
package test  //包的声明做好和所在的文件夹名相同

var TestNum int = 10  //首字母大写保证可以在包外访问

init 函数

init 函数在main函数前先被调用

第一步全局变量的定义

第二步init的定义

第三步 main函数的调用

image-20210611215216872

导入包时,先执行导入包文件中的init 最后执行main中的init

匿名函数

如果某个函数只是希望使用一次,可以使用匿名函数

在定义的时候就直接使用

func main() {
	方式1
         // 匿名函数  定义同时调用
   test:=func (a int,b int)(int){
      return a+b
      }(10,20)  //传入参数
   fmt.Println(test)  //输出30
   
   方式2
	//sub 等价于匿名函数
	sub := func(a int, b int) (int) {
		return a - b //传入参数

	}
	result := sub(30, 70)
	fmt.Println(result)

}

闭包

一个函数和与其相关的引入环境所组成的一个集合

闭包:返回的匿名函数+匿名函数以外的变量 就是闭包

// 声明函数    返回一个函数
func getsum() func (a int,)(int){
   var sum int =0
   
   return func(a int) int {
      sum =sum+a
      return sum
   }

}
func main() {

   f :=getsum()
   fmt.Println(f(1))   //返回1
   fmt.Println(f(2))  //返回3 此时sum为上次的1 1+2=3
   //匿名函数中引用的那个变量会一直保存在内存中,一直使用
}

defer关键字

在函数中需要创建资源,为了在函数执行完毕后,及时释放资源.go语言引入defer关键字

在go语言中遇到defer关键字,会将defer关键字中的语句压入栈中 同时将相关的值拷贝到栈中,函数执行结束后,从栈中取出(先进后出)执行

func test(a int){
   defer fmt.Println("1")
   defer fmt.Println(2)    //最后进栈,所以先弹出执行

   fmt.Println(a)   //第一个执行

}
func main() {
   test(3)
}

输出 3 2 1

func test(a int){
   defer fmt.Println(a)  //开始执行a =3 将执行结果压入栈中
   a+=2
   fmt.Println(a)

}
func main() {
   test(3)
}
输出 5  3

应用

连接数据库,将关闭连接的语句写到defer 后

系统函数

字符函数

len()

func main() {
   var s string ="你好"    //在go语言中汉字是UTF_8字符集,一个汉字3个字节
   fmt.Println(len(s))         //输出6
}

字符串遍历

func main() {
   var s string = "你好" //在go语言中汉字是UTF_8字符集,一个汉字3个字节

   for _, value := range s {  //返回索引 和对应的值
      fmt.Printf("值为:%c\n", value)     
   }
      //方式2
   //利用 []rune(变量) 进行切片
	r := []rune(s)
	for i:=0;i<len(r);i++{
		fmt.Printf("%c",r[i])
	}
}

字符串转换 strconv包

func main() {
   var s string = "1"
   //str 转 int
   num, err := strconv.Atoi(s)
   if err == nil {
      fmt.Println(num, err)
   } else {
      fmt.Println("111", err)
   }
   //int 转str
   str := strconv.Itoa(88)
   fmt.Println(str)
}

统计一个字符转总计的个数 导入->strings 包

func main() {
   var s string = "1231231233454"
   count := strings.Count(s, "1")
   fmt.Println(count)

   //不区分大小写的字符串比较
   fmt.Println(strings.EqualFold("go", "GO")) //返回true

   //返回字符在字符串中第一次出现的索引值
   fmt.Println(strings.Index("abcsac", "h")) //返回 0  不存在是返回 -1

   //字符串替换
   //strings.Replace("原字符","原替换字符","替换为",匹配替换次数)
   str := strings.Replace("abcabcabc", "a", "A", 2) //替换a 为 A 替换2次  全部替换时 n 传入-1
   fmt.Println(str)                                 //AbcAbcabc

   //字符串的切割返回一个数组
   str1 := strings.Split("abcabc", "a")
   fmt.Println(str1)  //输出[bc bc]
   for _, value := range str1 {
      fmt.Println(value)
   }

   //字符串大小写切换
   fmt.Println(strings.ToUpper("go"))  //小写转大写
   fmt.Println(strings.ToLower("GO"))  //大写转小写

   //去除左右两边的空格
   fmt.Println(strings.TrimSpace("   12 12   12    "))
   fmt.Println(strings.Trim("-go -","-"))  //去除左右两边指定字符串

   //判断是否已某个字符串开头
   fmt.Println(strings.HasPrefix("www.baidu.com","www"))  //返回bool 类型 true
   //判断是否已某个字符串结尾
   fmt.Println(strings.HasSuffix("www.baidu.com","com"))


}

日期函数 time 包

package main

import (
   "fmt"
   "time"
)

func main() {
   now := time.Now()
   fmt.Println(now)
   fmt.Printf("%v\n", now.Year())
   fmt.Printf("%v\n", int(now.Month())) //int 英文转数字
   //日期的格式化
   ///使用Sprintf 可以用字符串接收  Prinf 直接将信息输出
   str := fmt.Sprintf("%d-%d-%d %d-%d-%d\n", now.Year(), now.Month())
   fmt.Printf(str)
   
   //format 中数值必须这么写
   date1 := now.Format("2006-01-02 15:04:05")
   fmt.Printf(date1)

}

内置函数

new 用于分配内存 第一个参数为类型 ,返回一个类型的指针

func main() {
   //new 分配内存,new函数返回值是对应类型的指针 num *int
   num := new(int)
   *num=10
   fmt.Printf("%T",num)
   //num 指针的中存的对应内存地址,&num 取指针的内存地址,*num 去指针对应内存地址中对应的值
   fmt.Println(num,&num,*num)

}

错误处理机制 defer+recover 提高程序健壮性 类似try catch

func main() {
   test()  //防止test中程序错误导致程序中断
   fmt.Println("main"r)
}
func test() {
   
   defer func(){
      err := recover()
      //如果没有捕获到错误,返回值为0 :nil
      if err != nil {
         fmt.Println("err:", err)
      }
   }()
   
   num1 := 1
   num2 := 0
   result := num1 / num2 
   fmt.Println(result)
}

自定义错误

image-20210613113437160

数组

多种声明方式
var scores [5]int
var n [3]int = [3]int{1, 2, 3}
var n1 = [3]int{1, 2, 3}
var n2 = [...]{1: 1, 2: 22, 3: 33, 0: 44}  //下标 : 值
func test() {
   var scores [5]int   //声明数组
   scores[0] =15
   
   sum:=0
   for i,v :=range scores{
      fmt.Println(i)
  	  sum+=v
   }
   fmt.Println(sum)
   fmt.Println(scores)
}

image-20210614084359954

二维数组

var a[2][3]int   输出[[0,0,0] [0,0,0]]
var b [2][3]int = [2][3]int{{1,2,3},{1,2,3}}
二维数组遍历

func main() {
	var b [2][3]int = [2][3]int{{1, 2, 3}, {1, 2, 3}}
	fmt.Println(b)

	for i := 0; i < len(b); i++ {
		for j := 0; j < len(b[i]); j++ {
			fmt.Printf("b[%v][%v]=%v\t", i, j, b[i][j])
		}
	}

	for key, value := range b {
		for k, v := range value {
			fmt.Printf("b[%v][%v]=%v\t", key, k, v)
		}
	}
}

切片

func main() {
   var b [3]int = [3]int{1, 2, 3}
   c := b[1:2]  //切片操作
   fmt.Println(c)
}

原3,6,7,1,4,7

切片1:3 即 6 9 切片容量一般为切片的2倍

image-20210614105724574切片在内存中存储的是 原数据的内存地址

因此修改切片后的值会影响,原始数据中的值

 var b [3]int = [3]int{1, 2, 3}
   c := b[1:2]  //切片操作
   
fmt.Printf("%v\n", &b[1])
fmt.Printf("%v", &c[0])
两个值一致, 这块和python 也不一样

func main() {
   var b []int = []int{1, 2, 3}
   var c []int = make([]int,10)  //声明切片长度为10 的切片
   //c=b   //这种赋 内存中对应的地址一样,修改c中的数据会影响到b

   copy(c,b)  //将b数组拷贝进c  会形成两个数组,修改c不会影响b

   fmt.Printf("%v\t" ,&c[0])
   fmt.Printf("%v",&b[0])
   fmt.Println(c)
}

映射

map 键值对:一堆匹配的信息

func main() {
   //只声明map 内存是没有分配空间的  必须通过make 函数进行初始化,才会分配空间
   var a map[int]string
   //方式1 创建
   a = make(map[int]string,10)
   
   //方式2
   b:=make(map[int]string)
   //方式3
   c:=map[int]string{12:"张",13:"王"}

   a[12]="123"
   a[13]="234"
   fmt.Println(a)

   for key,values :=range a{

      fmt.Printf("%v:%v\n",key,values)

   }

map操作

map[key]=value

删除

delete(变量,key)

查找

value,bool_flag:=变量[值]

c:=map[int]string{12:"张",13:"王"}
c[14]="李"

delete(c,12)

value,bool_flg :=c[14]
fmt.Println(value,bool_flg)
fmt.Println(c)
func main() {

   c:=make(map[int]map[int]string) // [1:[1:李]]
   c[1]=make(map[int]string)
   c[1][1]="李"



   fmt.Println(c)
   for _,v:= range c{
      fmt.Println(v)

      for k1, v1 := range v{
         fmt.Println(k1,v1)
      }
   }
}

结构体

package main

import "fmt"
//定义结构体
type animal struct{
   name string
   age int
}
func main() {
   //擦混剪结构体的实例
   var cat animal
   cat.age=12
   cat.name="猫"

   //初始化并赋值
   var dog animal=animal{"狗",12}
   fmt.Println(dog)
   fmt.Println(cat)




}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值