Go基础笔记

Go

Linux下安装Go开发包

  1. 首先找到Go官网https://golang.google.cn/dl/

    在这里插入图片描述

    对于386的是32位OS的,所以针对自己的OS选择合适的安装包

  2. 选择安装目录通过cd命令切换到自己安装的目录

    [root@bogon ~]# cd /usr/local/
    [root@bogon local]# ll
    total 0
    drwxr-xr-x. 2 root root  6 Apr 11  2018 bin
    drwxr-xr-x. 2 root root  6 Apr 11  2018 etc
    drwxr-xr-x. 2 root root  6 Apr 11  2018 games
    drwxr-xr-x. 2 root root  6 Apr 11  2018 include
    drwxr-xr-x. 2 root root  6 Apr 11  2018 lib
    drwxr-xr-x. 2 root root  6 Apr 11  2018 lib64
    drwxr-xr-x. 2 root root  6 Apr 11  2018 libexec
    drwxr-xr-x. 2 root root  6 Apr 11  2018 sbin
    drwxr-xr-x. 5 root root 49 Nov  8 21:09 share
    drwxr-xr-x. 2 root root  6 Apr 11  2018 src
    
    
  3. 使用wget下载开发包

    [root@bogon local]# wget https://dl.google.com/go/go1.20.2.linux-amd64.tar.gz
    --2023-03-23 10:06:46--  https://dl.google.com/go/go1.20.2.linux-amd64.tar.gz
    Resolving dl.google.com (dl.google.com)... 58.254.149.161
    Connecting to dl.google.com (dl.google.com)|58.254.149.161|:443... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: 100107955 (95M) [application/x-gzip]
    Saving to: ‘go1.20.2.linux-amd64.tar.gz’
    
    100%[===============================================================>] 100,107,955 1.40MB/s   in 54s    
    
    2023-03-23 10:07:41 (1.77 MB/s) - ‘go1.20.2.linux-amd64.tar.gz’ saved [100107955/100107955]
    
    
  4. 通过tar命令对下载的包进行解压

    [root@bogon local]# tar -xzf go1.20.2.linux-amd64.tar.gz 
    [root@bogon local]# ll
    total 97764
    drwxr-xr-x.  2 root root         6 Apr 11  2018 bin
    drwxr-xr-x.  2 root root         6 Apr 11  2018 etc
    drwxr-xr-x.  2 root root         6 Apr 11  2018 games
    drwxr-xr-x. 10 root root       222 Mar  4 02:22 go
    -rw-r--r--.  1 root root 100107955 Mar  8 00:48 go1.20.2.linux-amd64.tar.gz
    drwxr-xr-x.  2 root root         6 Apr 11  2018 include
    drwxr-xr-x.  2 root root         6 Apr 11  2018 lib
    drwxr-xr-x.  2 root root         6 Apr 11  2018 lib64
    drwxr-xr-x.  2 root root         6 Apr 11  2018 libexec
    drwxr-xr-x.  2 root root         6 Apr 11  2018 sbin
    drwxr-xr-x.  5 root root        49 Nov  8 21:09 share
    
    
  5. 使用cd 命令进入该目录,然后执行bin/go version 命令就可以查看当前Go语言的版本了。

    [root@bogon local]# cd go/
    [root@bogon go]# ll
    total 52
    drwxr-xr-x.  2 root root  4096 Mar  4 02:21 api
    drwxr-xr-x.  2 root root    29 Mar  4 02:22 bin
    -rw-r--r--.  1 root root    52 Mar  4 02:19 codereview.cfg
    -rw-r--r--.  1 root root  1339 Mar  4 02:19 CONTRIBUTING.md
    drwxr-xr-x.  2 root root   104 Mar  4 02:21 doc
    drwxr-xr-x.  3 root root    18 Mar  4 02:21 lib
    -rw-r--r--.  1 root root  1479 Mar  4 02:19 LICENSE
    drwxr-xr-x. 11 root root   152 Mar  4 02:21 misc
    -rw-r--r--.  1 root root  1303 Mar  4 02:19 PATENTS
    drwxr-xr-x.  4 root root    33 Mar  4 02:22 pkg
    -rw-r--r--.  1 root root  1455 Mar  4 02:19 README.md
    -rw-r--r--.  1 root root   419 Mar  4 02:19 SECURITY.md
    drwxr-xr-x. 49 root root  4096 Mar  4 02:21 src
    drwxr-xr-x. 26 root root 12288 Mar  4 02:21 test
    -rw-r--r--.  1 root root     8 Mar  4 02:19 VERSION
    [root@bogon go]# bin/go version
    go version go1.20.2 linux/amd64
    
    
  6. 配置环境变量

    #在此需要配置两个环境变量GOROOT和PATH
    GOROOT 的值应该为Go语言的当前安装目录:export GOROOT=/usr/local/go
    PATH 为了方便使用Go语言命令和 Go 程序的可执行文件,需要追加其值:export PATH=$PATH:$GOROOT/bin:$GOBIN
    
    #将变量添加到profile文件中
    [root@bogon go]# vim /etc/profile
    将下面两行代码,加入到文件末尾
    export GOROOT=/usr/local/go
    export PATH=$PATH:$GOROOT/bin
    之后   :wq 保存并退出
    #在使用source命令是配置文件生效
    [root@bogon go]# source /etc/profile
    
    ##最后使用  go env命令若出现如下内容则安装成功
    [root@bogon go]# go env
    GO111MODULE=""
    GOARCH="amd64"
    GOBIN=""
    GOCACHE="/root/.cache/go-build"
    GOENV="/root/.config/go/env"
    GOEXE=""
    GOEXPERIMENT=""
    GOFLAGS=""
    GOHOSTARCH="amd64"
    GOHOSTOS="linux"
    GOINSECURE=""
    GOMODCACHE="/root/go/pkg/mod"
    GONOPROXY=""
    GONOSUMDB=""
    GOOS="linux"
    GOPATH="/root/go"
    GOPRIVATE=""
    GOPROXY="https://proxy.golang.org,direct"
    GOROOT="/usr/local/go"
    GOSUMDB="sum.golang.org"
    GOTMPDIR=""
    GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
    GOVCS=""
    GOVERSION="go1.20.2"
    GCCGO="gccgo"
    GOAMD64="v1"
    AR="ar"
    CC="gcc"
    CXX="g++"
    CGO_ENABLED="1"
    GOMOD="/dev/null"
    GOWORK=""
    CGO_CFLAGS="-O2 -g"
    CGO_CPPFLAGS=""
    CGO_CXXFLAGS="-O2 -g"
    CGO_FFLAGS="-O2 -g"
    CGO_LDFLAGS="-O2 -g"
    PKG_CONFIG="pkg-config"
    GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build1836596645=/tmp/go-build -gno-record-gcc-switches"
    

Go语言的并发是基于 goroutine 的,goroutine 类似于线程,但并非线程。可以将 goroutine 理解为一种虚拟线程。Go语言运行时会参与调度 goroutine,并将 goroutine 合理地分配到每个 CPU 中,最大限度地使用 CPU 性能。

多个 goroutine 中,Go语言使用通道(channel)进行通信,通道是一种内置的数据结构,可以让用户在不同的 goroutine 之间同步发送具有类型的消息。这让编程模型更倾向于在 goroutine 之间发送消息,而不是让多个 goroutine 争夺同一个数据的使用权。
在这里插入图片描述

Hello world

package main   \\ 声明文件属于main包

import "fmt"    \\ 导入fmt其是go中的一个的一个标准输入输出的库

func main() {
	fmt.Println("Hello world")
}

通过go build先编译后go run和直接go run的区别

  • 如果我们先编译生成了可执行的exe文件,那么我们可以将该可执行文件拷贝到其他没有go开发环境的机器上,仍然可以运行
  • 直接使用go run运行,该机器上必须有go的开发环境
  • 在编译时,编译器会将程序运行以来的库文件包含在可执行文件中,所以可执行文件会变大很多

Go开发注意事项

  1. Go的源文件是一“go”为扩展名的
  2. Go应用程序的执行入口是main()函数
  3. Go语言严格区分大小写
  4. Go方法是由一条条语句后塍,每个语句后不需要添加; 系统后自己加
  5. 在Go中定义的变量和import的包如果没有使用,代码不能通过编辑

转义字符

\\			   一个 \
\t			   制表符
\n			   换行
\r		       直接替换掉前面相应位数的字符

Go的注释

同java

命名规范

命名规则涉及变量、常量、全局函数、结构、接口、方法等的命名。

Go语言从语法层面进行了以下限定:

  • 任何需要对外暴露的名字必须以大写字母开头,不需要对外暴露的则应该以小写字母开头。

  • 当命名(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如: GetuserName ,那么使用这种形式的标识符的对象就

    可以被 外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面句对象语言中的 public );

  • 命名如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的 (像面向对象语言中的 private )

Go的关键字

在这里插入图片描述

1.Go的变量使用

  1. 指定变量的数据类型,但不赋值,使用默认值

    package main
    
    import "fmt"
    
    func main() {
    	// 只声明变量,不赋值
    	var i int
    	fmt.Println("i=", i)
    }
    
  2. 根据值自行判断数据的类型(类型推导)

    package main
    
    import "fmt"
    
    func main() {
    	//类型推导
    	var d = true
    	fmt.Println(d)
    }
    
  3. 使用 :=的方式,但此时的变量不能是声明过的,否则会报错
    在这里插入图片描述

    package main
    
    import "fmt"
    
    func main() {
    	name := "tom"  // 相当于 var name string = "tom"
        fmt.Println(name)
    }
    
  4. 一次声明多个变量

    package main
    
    import "fmt"
    
    func main(){
        //多个变量为同种数据类型
    	var n1,n2,n3 int
    	fmt.Println(" n1=", n1, "\n",
    		"n2=", n2, "\n",
    		"n3=", n3)
        //多个变量为不同种数据类型
        var name,age,local = "tom",21,false
        fmt.Println("name=",name,"age=",age,"local=",local)
    }
    
  5. 声明全局变量

    package main
    import "fmt"
    
    var (
    	name2 = "21"
    	age2 = 12
    )
    
    func main(){
    
    }
    

读取变量的大小,可以使用unsafe包中地Sizeof方法

package main

import (
	"fmt"
	"unsafe"
)

// 查看当前变量占用的字节数   unsafe.Sizeof(变量名)
func main() {
	c := "a"
	fmt.Printf("c的类型是  %T", unsafe.Sizeof(c))
}

全局变量和局部变量区别

  1. 定义位置不同,局部变量在函数内,全局变量在包下,函数外
  2. 存活时间不同,局部变量随函数的执行结束而销毁,全局变量随main函数存活
  3. 作用域不同。

在Go中字符串有所不同,其是由字节组成的

匿名变量

func main() {
	s := user.Hello()
	fmt.Printf("s: %v", s)

	_, age := getPerson()
	fmt.Printf("age: %v\n", age)

}

常量

const 常量名 数据类型 = value

一次性定义多个常量

const (
	a1 = 100
	a2
	a3
)
iota

iota在关键字const出现时被重置为0,const中每增加一行常量声明将使iota加一

举例:
1.跳过某些值

const (
	a1 = iota
	a2			//1
	a3			//2
	_				
	a4			//3
)

2.iota声明中间插队

const(
	a1 = iota   //0
	a2			//1
	a3 = iota   //2			
	_				
	a4			//3
)
  1. iota 定义在一行

    const(
    	a1,a2 = iota,iota+1   //0,1
    	a3 = iota       	  //1		
    	a4,a5 = iota+1 		  //3
    )
    
  2. 定义数量级

    const(
    	_ = iota 
    	KB = 1 << (10 * iota)
    	GB = 1 << (10 * iota)
    	TB = 1 << (10 * iota)
    	PB = 1 << (10 * iota)
    )
    

2.Go的数据类型

主要的数据类型分为2种,基本数据类型和派生/复杂数据类型

基本数据类型分为:整型、字符型、布尔型、字符串

派生/复杂数据类型:指针、数组、结构体、管道、函数、切片、接口、map类型

在这里插入图片描述

2 基本数据类型

2.1 使用细节

2.1.1整型

有符号:
在这里插入图片描述

无符号:
在这里插入图片描述

	b := -1
	//printf 是做格式化输出的   %T  相当于 Type
	fmt.Printf("b的类型是%T 占用的字节大小是 %d \n", b, unsafe.Sizeof(b))
	c := 111
    // 查看当前变量占用的字节数   unsafe.Sizeof(变量名)  
	fmt.Printf("c的类型是  %T 占用的字节大小是 %d", c, unsafe.Sizeof(c))

使用细节
  1. Golang各整数类型分: 有符号和无符号 ,int、uint(无符号)的大小和系统无关
  2. Go的整型默认声明为int
  3. Go中整型变量在使用是,遵守保小不保大的原则。即:保证程序正常运行下,尽量使用占用空间小的数据类型

2.1.2浮点型

在这里插入图片描述

  1. Go中浮点类型有固定的范围和字节长度,不受具体的OS的影响
  2. Go中的浮点类型默认是64位

注意:通长情况下使用的64位的,因为其更加精确

	var num4 = 1.2
	//打印num4的数据类型
	fmt.Printf("num4的数据类型是 %T ", num4)

	//科学计数法
	num5 := 5.123e2    // ->  5.123 * 10的2次方   e 大小写均可
	fmt.Println("num5:", num5)

2.1.3字符类型

字符串:就是一串固定长度的字符连接起来的字符序列

Go中没有专门的字符类型,如果要存储单个的字符(字母),一般使用byte来保存。

所以对比传统的字符串不同,在Go中字符串是由byte组成的。

注意:

  1. 对于保存的字符在ASCII表中的字符直接可以使用byte保存
  2. 若不在ASCII中,我们就要考虑int类型保存
  3. 需要输出字符的本身内容,使用格式化输出
package main

import (
	"fmt"
)

func main() {
	//c := "a"
	var c1 byte = 'a'

	fmt.Println("c1=", c1)
	//使用格式化输出,输出对应的字符
	fmt.Printf("c1=%c", c1)
    //在使用单个汉字时,由于byte的范围(0-255)有限,所以其数据类型int
    e := '别'
	fmt.Printf("e的数据类型是%T,e对应的码值是%d", e, e)
}

字符类型的使用细节:

  • 对于字符常量的使用用单引号引起该字符
  • Go中允许使用转义字符来讲特殊字符转为常量
  • Go语言使用的是UTF-8编码
  • 在Go中字符的本质就是一个整数,在直接输出是,是输出其对应的URF-8编码的编码值
  • 也可以直接给某一个变量赋一个数字,然后按照格式化输出会输出改数字对应的unicode字符
  • 字符类型是可以进行运算的,相当于一个整数,其有对应的Unicode
	e := '别'
	fmt.Printf("e的数据类型是%T,e对应的码值是%d \n", e, e)

	f := 97
	fmt.Printf("f=%c", f)

	c3 := 10 + 'a'
	fmt.Println(c3)

在这里插入图片描述

2.1.4布尔类型 bool

基本介绍
布尔类型也叫bool类型,bool类型数据只允许取值 true和false,其只占用一个字节

package main
import (
	"fmt"
	"unsafe"
)
func main() {
	b := false
	fmt.Printf("b的数据类型%T,占用的字节大小是%d", b, unsafe.Sizeof(b))
}

2.1.5字符串类型: string

基本介绍
字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的,Go语言的字符串的字节长度使用utf-8编码表示Unicode文本。

golang的字符串是由单个字节组成

	var name = "中华人民共和国"
	fmt.Printf("name的字节大小是%d", unsafe.Sizeof(name))
注意事项和使用细节
  1. 字符串一旦赋值并不可改变
  2. Go语言的字符串的字节使用的是UTF-8编码表示Unicode文本,这样Go中统一使用的是UTF-8编码
  3. 字符串有两种表现形式:
    1. 双引号:会识别转义字符
    2. 反引号:以字符串的原生形式输出,包括换行和特殊字符,可以实现防止攻击、输出源代码等效果。
  4. 字符串的拼接方式 使用“ + ”

在这里插入图片描述

注意当字符串过长时,在使用字符串拼接时,“+” 需要在上方

在这里插入图片描述

2.2 基本数据类型默认表

数据类型默认值
整型0
浮点型0
字符串“”
布尔类型false

eg:
在这里插入图片描述

位运算符

&: 同1为1,有0为0

|:同0为0,有1为1

^:相同为0,不同为1

<< : 左移运算符 对于左移运算符,左移n位,就是给原数扩大2的n次方倍。其功能把"<<“左边的运算数的各二进位全部左移若干位,由”<<"右边的数指定移动的位数,高位丢弃,低位补0。

“>>” : 右移运算符">>“是双目运算符。右移n位就是除以2的n次方。 其功能是把”>>“左边的运算数的各二进位全部右移若干位,”>>"右边的数指定移动的位数

A = 0011 1100
B = 0000 1101

A & B = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001

a = 60;b = 13
a = 0011 1100
b = 0000 1101

a & b = 0000 1100 12
a | b = 0011 1101 61
a ^ b = 0011 0010 49

其他运算符

在这里插入图片描述

运算符优先级

在这里插入图片描述

2.3 基本数据类型转换

在Go中不同于java/c不同类型的变量之间不能自动完成类型转换。(没有隐式转换)

2.3.1 基本语法:

表达式T(v) 将值v转换为类型T
T:就是数据类型
v:就是需要转换的变量

package main
import "fmt"
func main() {
	var i int64 = 100
	//将i转换为float
	var j float32 = float32(i)
	fmt.Printf("i=%v j=%v \n", i, j)
	fmt.Printf("i的数据类型是 %T,j的数据类型是 %T", i, j)
	var x int32= int32(j)
	fmt.Printf("x的数据类型是%T", x)
}

2.3.2使用细节

  1. Go中无论大转小还是小转大,都是可以转换的(但是在大转小时需要注意数据溢出)

  2. 被转换的事变量存储的数据,变量本身的数据类型没有发现变化

    var x int32= int32(j)  //即只是把j的值转换为了32位的大小,j本身的数据类型并没有发生任何变化
    

练习题

func main(){
 	var n1 int32 = 12
	var n2 int64
	var n3 int8
	n2 = n1 + 20  //编译不通过,n1是int32 而n2是64,所以在运算时需要类型转换
	n3 = n1 + 20
}




func main() {
	var n1 int32 = 12
	var n3 int8
	var n4 int8
	n4 = int8(n1) +127   //编译通过,但是结果会溢出,因为int8的范围是[-128-127]
	n3 = int8(n1) + 128  //编译不通过,因为128不是int8
}

在import中如果对于一个包我们并没有使用,但是又不想删掉写好的代码,那么可以使用“_” 来表示忽略

2.4 基本数据类型和string的转换

2.4.1 基本类型转String类型

  1. fmt.Sprintf(“%参数”,表达式)

    func Sprintf(format string, a ...interface{}) string
    //a ...interface 表示空接口,可以接收任何类型的数据
    

    Sprintf根据format参数生成格式化的字符串并返回该字符串。

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	var num1 = 123
    	var f float64 = 3.1
    	var b bool = true
    	var c byte = 'c'
    	//var str1 string
    	var str1 = fmt.Sprintf("%d", num1)
    	fmt.Println(str1)
    	fmt.Printf("str1=%v,str的数据类型%T \n", str1, str1)
    	var str2 = fmt.Sprintf("%f", f)
    	fmt.Printf("str2=%v,str2的数据类型%T \n", str2, str2)
    	var str3 = fmt.Sprintf("%t", b)
    	fmt.Printf("str3=%v,str3的数据类型%T \n", str3, str3)
    	var str4 = fmt.Sprintf("%c", c)
    	fmt.Printf("str3=%v,str4的数据类型%T \n", str4, str4)
    }
    
  2. 使用strconv包的函数

    方法:

    • func FormatBool(b bool) string

      	str0 = strconv.FormatBool(b)
      	fmt.Printf("str0=%q,str的数据类型%T \n", str0, str0)
      
    • func FormatInt(i int64, base int) string

    func FormatInt(i int64, base int) string
    
    eg:
    	var str string
    	str = strconv.FormatInt(int64(num1), 10)
    	fmt.Printf("str=%q,str的数据类型%T \n", str, str)
    

    ​ 返回i的base进制的字符串表示。base 必须在2到36之间,结果中会使用小写字母’a’到’z’表示大于10的数字。

    • func FormatFloat(f float64, fmt byte, prec, bitSize int) string

      func FormatFloat(f float64, fmt byte, prec, bitSize int) string
      

      函数将浮点数表示为字符串并返回。

      bitSize表示f的来源类型(32:float32、64:float64),会据此进行舍入。

      fmt表示格式:‘f’(-ddd.dddd)、‘b’(-ddddp±ddd,指数为二进制)、‘e’(-d.dddde±dd,十进制指数)、‘E’(-d.ddddE±dd,十进制指数)、‘g’(指数很大时用’e’格式,否则’f’格式)、‘G’(指数很大时用’E’格式,否则’f’格式)。

      prec控制精度(排除指数部分):对’f’、‘e’、‘E’,它表示小数点后的数字个数;对’g’、‘G’,它控制总的数字个数。如果prec 为-1,则代表使用最少数量的、但又必需的数字来表示f。

      	var str5 = strconv.FormatFloat(f, 'f', 10, 64)
      	fmt.Printf("str5=%q,str的数据类型%T \n", str5, str5)
      

    Itoa函数:将int转为string

    var num int = 123
    str = strconv.Itoa(num)
    fmt.Printf("str=%q,str的数据类型%T \n", str, str)
    
    

    2.4.2 String转基本类型

    1. 使用strconv包中的函数

      • func ParseInt
      func ParseInt(s string, base int, bitSize int) (i int64, err error)
      //eg:
      	str7 := "1234567"
      	var n1 int64
      	n1, _ = strconv.ParseInt(str7, 10, 64)
      	fmt.Printf("n1=%v,n1的数据类型是%T", n1, n1)
      

      返回字符串表示的整数值,接受正负号。

      base指定进制(2到36),如果base为0,则会从字符串前置判断,"0x"是16进制,"0"是8进制,否则是10进制;

      bitSize指定结果必须能无溢出赋值的整数类型,0、8、16、32、64 分别代表 int、int8、int16、int32、int64;返回的err是*NumErr类型的,如果语法有误,err.Error = ErrSyntax;如果结果超出类型范围err.Error = ErrRange。

      • func ParseUint
      func ParseUint(s string, base int, bitSize int) (n uint64, err error)
      

      ParseUint类似ParseInt但不接受正负号,用于无符号整型。

      • func ParseFloat
      func ParseFloat(s string, bitSize int) (f float64, err error)
      
      //eg
      	var str8 string = "78.322"
      	var f1 float64
      	f1, _ = strconv.ParseFloat(str8, 10)
      	fmt.Printf("f1=%v,f1的数据类型是%T \n", f1, f1)
      

      解析一个表示浮点数的字符串并返回其值。

      如果s合乎语法规则,函数会返回最为接近s表示值的一个浮点数(使用IEEE754规范舍入)。bitSize指定了期望的接收类型,32是float32(返回值可以不改变精确值的赋值给float32),64是float64;返回值err是*NumErr类型的,语法有误的,err.Error=ErrSyntax;结果超出表示范围的,返回值f为±Inf,err.Error= ErrRange。

      • func ParseBool
      func ParseBool(str string) (value bool, err error)
      // 在使用时,该函数有两个返回值,所以在接收时需要两个变量去接收,若我们只需要前一个返回值,对于后一个返回值,可以使用“_”来忽略掉。
      
      	var b1 bool
      	b1, _ = strconv.ParseBool(str0)
      	fmt.Printf("b=%v,b1的数据类型是%T", b1, b1)
      
      
      

      返回字符串表示的bool值。它接受1、0、t、f、T、F、true、false、True、False、TRUE、FALSE;否则返回错误。

      注意:

      在将string转为其他数据类型时,如出现无效的数据,Go会直接将其置为当前数据类型的默认值

      	var str9 string = "hello"
      	var n0 int64
      	n0, _ = strconv.ParseInt(str9, 10, 64)
      	fmt.Printf("n0=%v,n0的数据类型是%T \n", n0, n0)
      	//若是bool时会是默认值false
      

      运行结果:

      在这里插入图片描述

2.5复杂数据类型

2.5.1指针

2.5.2基本介绍
  1. 基本数据类型,变量存的就是值,也叫值类型
  2. 获取变量的地址,用&,比如 var num int,获取num的地址:&num
  3. 指针类型,变量存的就是一个地址,这个地址指向的空间存的才是值;比如 var ptr *int = &num
  4. 获取指针类型所指向的值,使用: * ,比如 var ptr int*,使用 *ptr获取p指向的值

在这里插入图片描述

代码:

	var i int = 10
	fmt.Printf("i: %v\n", i)
	fmt.Printf("i的地址是 %v \n", &i)

	var ptr *int = &i
	fmt.Printf("ptr 的地址是: %v\n", &ptr)

	//对于ptr本身是指向i变量的地址
	fmt.Printf("ptr: %v\n", ptr)

	//实际上ptr的值是i的值,
	fmt.Printf("ptr 的值是: %v\n", *ptr)
2.5.3 细节说明

在这里插入图片描述

2.6 值类型和引用类型

2.6.1 值类型

包括:基本数据类型、数组和结构体

值类型通常存储在栈内存中

2.6.2 引用类型

包括:指针、切片(slice)、map、管道(chan)、interface

引用类型数据通常存储在堆中

变量存储的都是一个地址,这个地址的空间对应的才是真正的数据,如果该地址没有被任何变量引用则会被认为垃圾回收。

2.7 数组

定义好之后,数组长度不可变

语法:

var 数组名 =  [长度]数据类型
var a1  = [2]int
var a2  = [3]string

var arr = [3]int {1,2,3}

数组的遍历

普通for循环

var arr = [3]int{1,2,3}

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

for range循环

for i, v := range arr{
	fmt.Printf("i is %v ,v is %v", i,v)
}

切片

3 if语法和循环

3.1 单分支语句

语法

if 条件 {
	执行语句
}

3.2 双分支语句

if 条件 {
	//条件为真执行
}else{
	//条件为假执行
}

3.3 嵌套语句

if 条件1 {
	//条件1为真执行
	if 条件2 {
	//条件2为真执行	
	}
}

4 函数

4.1函数定义

语法

func 函数名 (形参列表) (返回值列表) {  //返回值有多个要写括号,返回值可以是值类型或引用数据类型
	函数体
}

案例:

func OperatorNum(n1 float64, n2 float64, operator string) float64 {

	num1 := n1
	num2 := n2
	var operaor string = operator
	var res float64

	switch operaor {
	case "+":
		res = num1 + num2
	case "-":
		res = num1 - num2
	case "*":
		res = num1 * num2
	case "/":
		res = num1 / num2
	default:
		fmt.Print("input is error")
	}
	return res
}

4.1.1包

包的作用:

  1. 区分相同名字的函数,变量等标识符
  2. 进行项目管理
  3. 控制函数、变量等访问范围,即作用域
使用细节:
  • 包名过长给包名起别名
import (
	"fmt"
	别名 "包名"
)
  • 同一个包中不允许有同名的函数(也不能有相同的全局变量名)

  • 包中函数访问方式

    包名.函数名
    
  • 如果要编译成一个可执行文件,就需要将这个包声明成main

    D:\Go>  go build -o bin\xx.exe go_pro\包名\main
    

//针对函数中的返回值,如果有返回值,不需要,可以使用_ 忽略

func main() {
	// name := example.InputFunc()
	// fmt.Printf("name: %v\n", name)
	_, sub := GetSum(1, 2)
	fmt.Printf("sum: %v\n", sub)

}
猴子吃桃子问题

有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!以后每天猴子都吃其中的一半,然后再多吃一个。当到第十天时,想再吃时 (还没吃) ,发现只有1个桃子了。问题: 最初共多少个桃子?

// 10:  =>   1
// 9:   =>   (第10天的桃子+1) * 2
// 8:   =>   (第9天的桃子 + 1) * 2

// 第n天的桃子数:      =>    (第n+ 1天的桃子 + 1) *2
func eatPaeach(n int) int {
	if n == 10 {
		return 1
	} else {
		return (eatPaeach(n+1) + 1) * 2
	}
}

func main() {
	fmt.Printf("res: %v\n", eatPaeach(9))
}

4.2 函数使用细节

  1. 返回值有多个。当有多个时要写括号,返回值可以是值类型或引用数据类型

  2. 函数名首字母大写,任何地方可以访问,函数名首字母小写,只有本包可以使用

  3. 函数内定义的变量是局部变量,只能在函数内使用

  4. 基本数据类型和数组默认都是值传递的,即进行值拷贝。在函数内修改,不会影响到原来的值

    func test(n1 int) {
    	n1 += 10
    	fmt.Printf("test()n1: %v\n", n1)
    	fmt.Println(&n1)
    }
    func main() {
    	num := 10
    	test(num)
    	fmt.Printf("main() num is %v", num)
    	fmt.Println(&num)
    
    }
    
  5. 如果要在函数内修改当前形参接受的实参的数据(实参是基本数据类型或者数组),那么可以传入实参的地址,函数内以指针的方式操作变量。

    func test(n1 *int) {
    	*n1 += 10
    	fmt.Printf("test()n1: %v\n", *n1)
    	// fmt.Println(&n1)
    }
    
    func main() {
    	num := 10
    	test(&num)
    	fmt.Printf("main() num is %v", num)
    
  6. Go中不支持函数的重载

  7. 函数也是一种特殊的数据类型,可以将函数赋值给变量,通过变量,可以完成对函数的调用。(闭包)

    func test01(n1 int) int {
    	return n1
    }
    
    func main() {
    	num := 1
    	a := test01
    	fmt.Printf("a type is %T\t test type is %T", a, test01)
        //通过变量访问函数
    	res := a(num)
    	fmt.Printf("res: %T\n", res)
    }
    

    输出:在这里插入图片描述

  8. 函数既然是数据类型,那么函数就可以当做形参使用,并且调用

    func test01(n1 int) int {
    	return n1
    }
    
    func myfunc(funcvar func(int) int,num int ) int{
    	reutrn funcvar(num1)
    }
    
    func main() {
    	num := 1
    	a := test01
    	//fmt.Printf("a type is %T\t test type is %T", a, test01)
        //通过变量访问函数
    	//res := a(num)
    	//fmt.Printf("res: %T\n", res)
    	
    	res2 := myfunc(test01, num)
    	fmt.Printf("res: %T %v\n", res2, res2)
    }
    
  9. 为了简化数据类型定义,Go支持自定义数据类型

    type 变量名  数据类型
    

4.3 init函数

初始化函数,是在main函数执行之前执行

细节
  1. 如果一个文件中同时包含全局变量定义。init函数和main函数,则执行顺序是:变量定义=> init函数 => main函数
  2. 作用:完成一些初始化的工作
4.3.1 go文件执行流程:
  • 首先执行,被引入包的函数,开始变量定义执行init函数
  • 在执行引入其他包的函数中的变量执行,之后init初始化,最后执行main

在这里插入图片描述

4.4 匿名函数

当函数只使用一次时,可以考虑使用匿名函数

方式一:

res := func (n1 int,n2 int) int {
	return n1+n2
}(10,20)

方式二:

res := function(n1 int,n2 int) int){
	return n1 + n2
}


sum := res(10,20)

全局匿名函数

将一个匿名函数交给一个全局变量

var (
	Func = function(n1 int,n2 int) int){
		return n1 + n2
    }
)

5 闭包

其是一个函数和与其相关的引用环境组合成的一个整体

内层函数+外层变量
示例:
在这里插入图片描述

func makeSuffix(suffix string) func(string) string {
	return func(name string) string {
		if !strings.HasSuffix(name, suffix) {
			return name + suffix
		}
		return name
	}
}

func main() {
	f := makeSuffix(".jpg")
	fmt.Println("文件处理后= ", f("winter"))
}

在这里插入图片描述

defer关键字

当执行到defer是,暂时不执行,会将defer后面的语句压入到独立的栈中,当函数执行结束之后,再从defer中按照先入后出的方式出栈

注意:

当defer语句放入到栈中,会将相关的值拷贝同时入栈

系统函数:

  1. len() 统计字符串长度,按照字节统计;其中不可以包含中文

  2. []rune(str) 字符串遍历,将字符串返回为一个切片,其中可以包含中文

  3. 字符串转为整型
    n, err := strconv.Atoi(“66”)

  4. 整数转为字符串:

    str = strconv.Itoa(“12345”)

  5. 查找子串是否在指定的字符串中:
    strings.Contains(“javagopython”,"go)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小张不会打篮球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值