一、安装Go
1.1、mac 上安装go
mac下载地址:https://golang.org/dl/go1.15.5.darwin-amd64.pkg
mac版下载完毕后直接安装。默认放在 /usr/local/go/ 目录下 (重开iterm窗口即可默认生效。)
1.2、win上安装go
地址:https://go.dev/dl/go1.21.1.windows-amd64.msi
安装路径放在"D:\Go"
二、配置GOROOT
2.1、mac使用默认路径 /usr/local/go 路径即可
2.2、mac使用默认路径"D:\Go"路径即可
三、配置GOPATH(GOPATH是一个环境变量)
WIN默认路径是:"C:\Users\xxx\go"
在用户环境变量中,修改GOPATH路径为:"E:\Goland_Document"
在"E:\Goland_Document"目录下依次新建目录"bin pkg src"三个目录
在用户环境变量Path中,新增:"E:\Goland_Document\bin"
MAC默认路径是:/Users/xxxxxx/go 当前的用户家目录下的go目录。
3.1、自定义修改
可使用 go env 命令查看当前go相关的环境变量
可编辑 ~/.bash_profile 目录设置 GOPATH 的路径。
export GOPATH=/Users/xxxxx/Desktop/Go/GoPath/go
生效:source ~/.bash_profile
不过这种方式只是临时生效。
3.2、使用默认的目录
在默认的 /Users/xxxxxx/go 目录下一次创建:bin,pkg,src 目录
3.3、查看go的环境变量相关信息,使用:go env
3.4、开发结构,一般用域名来区分不同的包
四、GO的编译
4.1、go build # 编译成可执行文件
将当前目录下的go代码文件编译为二进制文件(编译后的可执行文件名,为当前文件所在父目录)
编译后的可执行文件,直接执行:
4.2、go build -o "test.exe" # 编译后的文件重命名
将编译的可执行文件重命名为 "test.exe"
4.3、go run "main.go" # 运行xx.go文件
运行go代码文件
报错:
如果go env里面的"set GOOS=linux"时,那么执行go run "main.go" 会报错:
exec: "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build2764083230\\b001\\exe\\main": file does
此时需要将GOOS=linux,更改为GOOS=windows
执行命令 go env -w GOOS=windows
然后重新执行go run "main.go"即可
4.4、go install
分为2个步骤
1.先编译得到一个可执行文件,
2.将可执行文件移动到 GOPATH/bin 目录下。
4.5、编译 linux 和 windows 平台64位可执行程序
编译后的可执行文件在linux服务器上运行
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build
编译后的可执行文件在windows服务器上运行
SET CGO_ENABLED=0SET GOOS=windows
SET GOARCH=amd64
go build
五、GO的基础语法
5.1、注释
// 单行注释
/*
多行注释
*/5.2、go代码
// 当前程序的包名 package main //导入包 import "fmt" //函数外只能放置标识符(变量|常量|函数|类型)的声明 //同时导入多个包: import ( "fmt" "math" ) //程序的入口 func main() { fmt.Println("Test") }
5.2.1、代码关键字说明
package main
package是一个关键字,用来声明文件属于哪个"包",main是"包名"。(在go中,每个文件都必须归属一个"包")
同时main表示当前文件被编译后是一个可执行的文件。
同时代码还需要一个函数func main(){}作为入口。
import "fmt"
引入一个"包",使用该"包"的功能。
func main(){}
func是关键字,表示main是一个函数,"main"是函数名称,是一个主函数,是当前程序的入口。
5.3、关键字
通过 const 关键字来进行常量的定义。
通过在函数体外部使用 var 关键字来进行全局变量的声明和赋值。
通过 type 关键字来进行结构(struct)和接口(interface)的声明。
通过 func 关键字来进行函数的声明。
六、变量和常量
6.1、变量:Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。
1、变量的命名方式:var 变量名 变量类型
2、变量类型:常见变量的数据类型有:整数型、浮点型、布尔型等(Go语言中的每一个变量都有自己的类型)
3、变量声明:变量必须经过声明才能开始使用,并且Go语言的变量声明后必须使用
变量声明以关键字var开头,变量类型放在变量的后面,行尾无需分号。例子:
var name string
var age int
var isOk bool
批量变量声明
var (
aaa string
bbb int
ccc bool
ddd float32
)4、变量赋值(方式1)
Go语言在声明变量的时候,会自动对变量对应的内存区域进行初始化操作。每个变量会被初始化成其类型的默认值例如: 整型和浮点型变量的默认值为0。 字符串变量的默认值为空字符串。 布尔型变量默认为false。 切片、函数、指针变量的默认为nil。
变量赋值格式:var 变量名 变量类型 = 表达式
举个例子:
var name string = "Q1mi"
var age int = 185、变量类型推导(简化变量赋值)(方式2)
有时候我们会将变量的类型省略,这个时候编译器会根据等号右边的值来推导变量的类型完成初始化。例子:
var name = "Q1mi"
var age = 18一次对多个变量同时赋值(方法1)
var name, age = "sudada", 20一次对多个变量同时赋值(方法2)
var (
name = "sudada"
age = 20
)
6、短变量声明(:=)只能在函数内部使用(方式3,函数内使用)
在函数内部,可以使用更简略的 " := " 方式声明并初始化变量。例子:
name := "Q1mi"
age := 18一次对多个变量同时赋值
name, age := "sudada", 27、匿名变量
在使用多重赋值时,如果想要忽略某个值,可以使用匿名变量(anonymous variable)。 匿名变量用一个下划线_表示,例如:func foo() (int, string) { return 10, "Q1mi" } func main() { x, _ := foo() _, y := foo() fmt.Println("x=", x) fmt.Println("y=", y) }
匿名变量不占用命名空间,不会分配内存,所以匿名变量之间不存在重复声明。 (在Lua等编程语言里,匿名变量也被叫做哑元变量。)
注意事项:
函数外的每个语句都必须以关键字开始(var、const、func等)
:= 不能使用在函数外。
_ 多用于占位,表示忽略值。package main import "fmt" var name = "sudada" var age = 18 var isOk = false //变量声明后必须使用 func main() { name = "理想" age = 18 isOk = true fmt.Println(isOk) //直接打印输出,无换行符 fmt.Println(age) //直接打印输出,有换行符 fmt.Printf("name:%s", name) // %s:占位符 使用name这个变量的值去替换占位符,无换行符 fmt.Println() //短变量声明,只能在函数内使用,不能在全局使用 A := "aa" B := "bb" fmt.Println(A) fmt.Println(B) }
6.2、常量
常量是一个简单值的标识符,在程序运行时,不会被修改的量,
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
1、变量的命名方式:const 变量名 变量类型 =常量的值
2、相对于变量,常量是恒定不变的值,常量在定义的时候必须赋值:
const pi float64 = 3.14
const e int = 1113、声明了pi和e这两个常量并赋值之后,在程序运行期间常量的值不能再修改了。
多个常量也可以一起声明:
const (
pi = 3.14
e = 111
)4、const同时声明多个常量时,如果省略了值则表示和上面一行的值相同。 例如:
const (
n1 = 100
n2
n3
)5、常量只能修饰bool,数值类型(int,float系列),string类型
上面示例中,常量n1、n2、n3的值都是100。package main import "fmt" const pi = 11.111 const ( status = 200 notfound = 404 ) const ( n1 = 100 n2 n3 ) func main() { fmt.Println(pi) fmt.Println(status) fmt.Println(notfound) fmt.Println(n1) fmt.Println(n2) fmt.Println(n3) }
6.3、iota ( iota是go语言的常量计数器,只能在常量的表达式中使用 )
1、iota在const关键字出现时将被重置为0。const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。 使用iota能简化定义,在定义枚举时很有用。举个例子:
const (
n1 = iota //0
n2 //1
n3 //2
n4 //3
)2、几个常见的iota示例:使用_跳过某些值
const (
n1 = iota //0
n2 //1
_
n4 //3
)3、iota声明中间插队
const (
n1 = iota //0
n2 = 100 //100
n3 = iota //2
n4 //3
)
const n5 = iota //0package main import "fmt" const ( a1 = iota //0 a2 //1 a3 //2 ) const ( b1 = iota //0 b2 //1 _ b4 //3 ) const ( c1 = iota //0 c2 = 100 //100 c3 = iota //2 c4 //3 ) const n5 = iota //0 func main() { fmt.Println("a3:", a3) fmt.Println(a2) fmt.Println(a3) fmt.Println("b4:", b4) fmt.Println("c4:", c4) }
4、iota 的使用例子
1)、iota 单行使用时,计数测试(单行计数+1次)
package main import "fmt" const ( d1 = iota + 1 // 0+1=1 d2 = iota + 2 // 1+2=3 d3 = iota + 1 // 2+1=3 d4 = iota + 2 // 3+2=5 ) func main() { fmt.Println("d1: ", d1) fmt.Println("d2: ", d2) fmt.Println("d3: ", d3) fmt.Println("d4: ", d4) } //d1: 1 //d2: 3 //d3: 3 //d4: 5
2)、iota 一行有2个iota时,计数测试(单行计数+1次)
package main import "fmt" const ( szq1, szq2 = iota + 1, iota + 2 // 0+1=1, 0+2=2 szq3, szq4 = iota + 1, iota + 2 // 1+1=2, 1+2=3 ) func main() { fmt.Println("szq1: ", szq1) fmt.Println("szq2: ", szq2) fmt.Println("szq3: ", szq3) fmt.Println("szq4: ", szq4) } //szq1: 1 //szq2: 2 //szq3: 2 //szq4: 3
3)iota 只是在同一个 const 常量组内递增,每当有新的 const 关键字时,iota 计数会重新开始。
package main const ( i = iota j = iota x = iota ) const xx = iota const yy = iota func main() { println(i, j, x, xx, yy) } // 输出是 0 1 2 0 0
七、GO的基本数据类型(Golang程序在定义变量时,经量使用占用空间小的数据类型)
7.1、Go 语言按类别有以下几种基本数据类型:
序号 类型和描述 1 布尔型 bool
布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。默认值为 false2 数字类型
整数型 int32 int64 默认值为 0浮点型 float32、float64(默认使用) 默认值为 0
Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码
3 字符串类型 string
字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。默认值为 "空"
序号 类型和描述 1 byte(一般接收单个字符串的场景使用),详见12.1例子2
类似 uint8(有符号 8 位整型 (-128 到 127))2 rune(一般接收单个字符串的场景使用),详见12.1例子2
类似 int32(有符号 32 位整型 (-2147483648 到 2147483647))
序号 类型和描述 1 uint8
无符号 8 位整型 (0 到 255)2 uint16
无符号 16 位整型 (0 到 65535)3 uint32
无符号 32 位整型 (0 到 4294967295)4 uint64
无符号 64 位整型 (0 到 18446744073709551615)5 int8
有符号 8 位整型 (-128 到 127)6 int16
有符号 16 位整型 (-32768 到 32767)7 int32(一般接收单个字符串的场景使用),详见12.1例子2
有符号 32 位整型 (-2147483648 到 2147483647)8 int64
有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)7.2、格式化
%T:查看数据类型
%b:二进制数%o:八进制数
%d:十进制数
%x:十六进制数
%c:字符
%s:字符串
%p:指针
%v:值
%f:浮点数常用的有:
%T 查看数据类型 (例子:fmt.Printf("%T",num) 查看变量num的数据类型 )
%v 查看变量的值(value),万能用法
%s 字符串类型的变量去替代
%d 整数类型的变量去替代
%t bool类型的变量去替代unsafe.Sizeof(变量名) 变量占用的字节大小
package main import ( "fmt" "unsafe" ) func main() { num := 3 fmt.Printf("%T \n",num) // 查看变量num的数据类型,返回值:int fmt.Printf("%v \n",num) // 返回值:3 fmt.Printf("%d \n",num) // 返回值:3 fmt.Println(unsafe.Sizeof(num)) // 查看变量num占用的"字节大小",返回值:8 name := "sudada" fmt.Printf("%T \n",name) // 查看变量name的数据类型,返回值:string fmt.Printf("%v \n",name) // 返回值:sudada fmt.Printf("%s \n",name) // 返回值:sudada fmt.Println(unsafe.Sizeof(name)) // 查看变量name占用的"字节大小",返回值:16 }
7.3、指针类型(变量的内存地址)
& 取出变量的内存地址
* 根据内存地址取出对应的值
func main() { var str string = "sudada" var num int = 10 // 获取变量的指针地址,使用 & fmt.Println(&str) // 返回值:0xc000024070 fmt.Println(&num) // 返回值:0xc00000a0e8 // 变量类型为"指针类型": *int // 变量ptr的值是变量"num"指针地址: &num var ptr *int = &num fmt.Println(ptr) // 返回值:0xc00000a0e8 // 获取指针变量的值,使用 * fmt.Println(*ptr) // 返回值:10 }
例子1:将"变量的内存地址对应的值"修改后,"变量的值"就等于修改后的值
func main() { var num int = 10 fmt.Println(num) // 返回值:10 // 变量ptr的值就是变量num的指针地址 var ptr *int = &num // *ptr 拿到num的内存地址的值10,并给num重新赋值为11 *ptr = 11 // 此时num的值为11 fmt.Println(num) // 返回值:11 fmt.Println(*ptr) // 返回值:11 }
例子2:将"变量的内存地址对应的值"修改后,"变量的值"就等于修改后的值
func main() { var a int = 300 var b int = 400 var ptr1 *int = &a // 给变量ptr1赋值为a的内存地址 *ptr1 = 100 // 此时a = 100 ptr1 = &b // 给变量ptr1重新赋值为b的内存地址 *ptr1 = 200 // 此时b = 200 fmt.Printf("%v %v \n",a,b) // 返回值:100 200 }
7.4、值类型和引用类型
1)值类型:int,float,bool,string,数组,结构体struct
变量直接存储值,内存通常在栈中分配。
2)引用类型:指针,slice切片,map,管道chanel,接口interface
变量存储是一个内存地址,这个地址对应的空间是真正存储数据的值,内存通常在堆上分配,当没有任何变量引用这个地址时,那么这个内存地址会被垃圾回收。
八、字符串
8.1、字符串
Go 语言里的字符串的内部实现使用UTF-8编码。 字符串的值为 双引号"" 中的内容
例如:
s1 := "hello"
s2 := "你好"8.2、字符()
写法:'xxx' ,其中xxx是字符内容,单独的字母,汉字,符号 都表示一个字符。
例如:
a1 := 'a'
b1 := '1'
c1 := '苏'8.3、字符串转义符
Go 语言的字符串常见转义符包含回车、换行、单双引号、制表符等,如下表所示。
转义符 含义 \r
回车符(返回行首)例子:fmt.Println("abc\rdef"),打印的是"def","回车"会把"abc"覆盖掉 \n
换行符(直接跳到下一行的同列位置) \t
制表符,一个tab,实现代码对其的功能 \'
单引号 \"
双引号 \\
反斜杠 举个例子,我们要打印一个Windows平台下的一个文件路径:
package main import ( "fmt" ) func main() { fmt.Println("str := \"c:\\Code\\lesson1\\go.exe\"") } // str := "c:\Code\lesson1\go.exe"
8.4、多行字符串
Go语言中要定义一个多行字符串时,就必须使用 反引号`` 字符(反引号内的内容原样输出):func main() { s1 := `第一行 第二行 第三行 ` fmt.Println(s1) } //第一行 //第二行 //第三行
8.5、字符串的常用操作
方法 介绍 len(str) 字符串长度 + 或 fmt.Sprintf 拼接字符串 strings.Split 分割 strings.contains 判断是否包含 strings.HasPrefix,strings.HasSuffix 前缀/后缀判断 strings.Index(),strings.LastIndex() 子串出现的位置 strings.Join(a[]string, sep string) join操作 func main() { // 字符串相关操作len() s1 := `sudada` fmt.Println(len(s1)) // 6 // 字符串拼接 name := "lixiang" world := "dsb" test1 := name + world // 字符串直接拼接 fmt.Println(test1) // lixiangdsb test2 := fmt.Sprintf("%s%s", name, world) // 字符串拼接完毕后作为一个返回值 fmt.Println(test2) // lixiangdsb // 字符串分割,使用 strings.Split("要分割的对象", "分隔符") sudada := "c:\\Code\\lesson1\\go.exe\\" szq := strings.Split(sudada, "\\") fmt.Println(szq) // [c: Code lesson1 go.exe ] // 判断一个值,是否被包含,返回 true | false fmt.Println(strings.Contains(sudada, "go")) // true // 拼接 join:把字符串做拼接 fmt.Println(strings.Join(szq, "+")) // 拼接前:[c: Code lesson1 go.exe ] // 拼接后:c:+Code+lesson1+go.exe+ }
8.6、字符串去除空格和换行符
func main() { str := "这里是 www\n.runoob\n.com" fmt.Println("-------- 原字符串 ----------") fmt.Println(str) // 去除空格 str = strings.Replace(str, " ", "", -1) // 去除换行符 str = strings.Replace(str, "\n", "", -1) fmt.Println("-------- 去除空格与换行后 ----------") fmt.Println(str) }
九、基本数据类型的转换
9.1、int类型转float类型
func main() { // int类型转float类型 var a int = 100 var b = float64(a) fmt.Printf("%v %T \n",a,a) // 返回值:100 int fmt.Printf("%v %T \n",b,b) // 返回值:100 float64 }
9.2、基本数据类型(int bool float) 转换为 string类型
import ( "fmt" "strconv" ) func main() { var num1 int64 = 100 var float1 float64 = 10.123 var b bool = false var str string // int类型转string类型 //方式1,使用"fmt.Sprintf"方法 str = fmt.Sprintf("%d", num1) fmt.Printf("%v %T \n",str,str) // 返回值:100 string // float类型转string类型 str = fmt.Sprintf("%f", float1) fmt.Printf("%v %T \n",str,str) // 返回值:10.123000 string // bool类型转string类型 str = fmt.Sprintf("%t", b) fmt.Printf("%v %T \n",str,str) // 返回值:false string // int类型转string类型 //方式2,使用"strconv"方函数 str = strconv.FormatInt(num1,10) // 10表示10进制 fmt.Printf("%v %T \n",str,str) // 返回值:100 string // float类型转string类型 str = strconv.FormatFloat(float1,'f',10,64) // f 格式,10表示保留10位小数,64表示float64 fmt.Printf("%v %T \n",str,str) // 返回值:10.1230000000 string // bool类型转string类型 str = strconv.FormatBool(b) fmt.Printf("%v %T \n",str,str) // 返回值:false string }
9.3、string类型 转换为 基本数据类型(int bool float)
import ( "fmt" "strconv" ) func main() { var str1 string = "true" var b bool // string类型转bool类型 b,_ = strconv.ParseBool(str1) // 函数返回了2个值(value bool, err error) fmt.Printf("%T %v \n",b,b) // 返回值:bool true var str2 string = "100" var i int64 // string类型转int类型 i,_ = strconv.ParseInt(str2,10, 64) fmt.Printf("%T %v \n",i,i) // 返回值:int64 100 // string类型转float类型 var str3 string = "10.123" var f float64 f,_ = strconv.ParseFloat(str3,64) fmt.Printf("%T %v \n",f,f) // 返回值:float64 10.123 }
注意事项:string在转换为基本数据类型时,确保string类型能够转换为有效的数据。
十、运算符
10.1、算术运算符
注意:
++
(自增)和--
(自减)在Go语言中是单独的语句,并不是运算符++ 和 -- 只能写在变量的后面,即:a++ 或 a-- 不能写成:++a 或 --a
案例
func main() { // ++ 和 -- 的使用 var i int = 10 i++ fmt.Println(i) // 返回值:10 + 1 = 11 i-- fmt.Println(i) // 返回值:11 - 1 = 10 // 变量赋值 var num int = 10 num++ a := num // 不能写成:a := num++ fmt.Println(a) // 返回值:11 num-- b := num // 不能写成:a := num-- fmt.Println(b) // 返回值:10 }
运算符 描述 + 相加 - 相减 * 相乘 / 相除 % 取余 案例
func main() { // 除法运算:整数和整数做除法运算时,会把得到的结果去掉小数部分,只保留整数部分。 fmt.Println(10/4) // 10除4等于2.5,去掉小数0.5,那么返回值为:2 // 怎么保留小数部分,需要有浮点数参与运算 fmt.Println(10.0/4) // 返回值:2.5 fmt.Println(10/4.0) // 返回值:2.5 // 取余运算 // 公式:a * b = a - (a / b * b) fmt.Println(10%3) // 返回值:1 fmt.Println(-10%3) // 返回值:-1 fmt.Println(10%-3) // 返回值:1 fmt.Println(-10%-3) // 返回值:-1 }
10.2、关系运算符
运算符 描述 == 检查两个值是否相等,如果相等返回 True 否则返回 False。 != 检查两个值是否不相等,如果不相等返回 True 否则返回 False。 > 检查左边值是否大于右边值,如果是返回 True 否则返回 False。 >= 检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。 < 检查左边值是否小于右边值,如果是返回 True 否则返回 False。 <= 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。
10.3、逻辑运算符
A = True B=Flase
运算符 描述 && 逻辑 AND 运算符。 如果两边的操作数都是 True,则为 True,否则为 False。例子:(A && B),返回值为False || 逻辑 OR 运算符。 如果两边的操作数有一个 True,则为 True,否则为 False。例子:(A || B),返回值为True ! 逻辑 NOT 运算符。 如果条件为 True,则为 False,否则为 True。例子:!(A && B),返回值为True
二进制:0,1,满2进1
十进制:0-9,满10进1
八进制:0-7,满8进1,以数字0开头表示
十六进制:0-9及A-F,满16进1,以0x或0X开头,A-F不区分大小写。
二进制转十进制:
从最低位开始(右边),将每个位上的数提取出来,乘以2的(位数-1)次方,然后求和
案例:二进制 1011 转为十进制的数字
1011 = 1 * 2(0次方=1) + 1 * 2(1次方=2) + 0 * 2(2次方=4) + 1 * 2(3次方=8) = 1 + 2 + 0 + 8 = 11
八进制转十进制:
从最低位开始(右边),将每个位上的数提取出来,乘以8的(位数-1)次方,然后求和
案例:八进制 0123 转为十进制的数字
0123 = 3 * 8(0次方=1) + 2 * 8(1次方=8) + 1 * 8(2次方=64) + 0 * 8(3次方=0) = 3 + 16 + 64 + 0 = 83
十六进制转十进制:
从最低位开始,将每个位上的数提取出来,乘以16的(位数-1)次方,然后求和
案例:十六进制 0x34A 转为十进制的数字
0x34A = 10 * 16(0次方=1) + 4 * 16(1次方=16) + 3 * 16(2次方=256) = 10 + 64 + 768 = 842
十进制转二进制:
将该数不断除以2,直到商为0为止,然后将每步得到的余数倒过来,就是对应的二进制
案例:十进制 56 转为二进制
56 = 111000
十进制转八进制:
将该数不断除以8,直到商为0为止,然后将每步得到的余数倒过来,就是对应的八进制
案例:十进制 156 转为八进制
156 = 0234
十进制转十六进制:
将该数不断除以16,直到商为0为止,然后将每步得到的余数倒过来,就是对应的十六进制
案例:十进制 356 转为十六进制
356 = 164
二进制转八进制:
将二进制数每三位一组(从低位开始组合),转成对应的八进制数即可。
案例:二进制 11010101 转为八进制
11010101 = 325
二进制转十六进制:
将二进制数每四位一组(从低位开始组合),转成对应的十六进制数即可。
案例:二进制 11010101 转为十六进制
11010101 = 0xD5
八进制转二进制:
将八进制数每1位,转成对应的一个3位的二进制数即可。
案例:八进制 0237 转为二进制
0237 = 10011111
十六进制转二进制:
将十六进制数每1位,转成对应的一个4位的二进制数即可。
案例:十六进制 0x237 转为二进制
0x0237 = 1000110111
10.4、位运算符
位运算符对整数在内存中的二进制位进行操作。
运算符 描述 & 参与运算的两数各对应的二进位相与。
(两位均为1才为1,否则为0)| 参与运算的两数各对应的二进位相或。
(两位有一个为1就为1,两位都不为1则为0)^ 参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。
(两位不一样则为1,两位一样则为0)<< 左移n位就是乘以2的n次方。
“a<<b”是把a的各二进位全部左移b位,高位丢弃,低位补0。>> 右移n位就是除以2的n次方。
“a>>b”是把a的各二进位全部右移b位。
10.5、赋值运算符
例子
运算符 描述 = 简单的赋值运算符,将一个表达式的值赋给一个左值。例子:C=A+B += 相加后再赋值。例子:C+=A 等于 C=C+A -= 相减后再赋值。例子:C-=A 等于 C=C-A *= 相乘后再赋值。例子:C*=A 等于 C=C*A /= 相除后再赋值。例子:C/=A 等于 C=C/A %= 求余后再赋值。例子:C%=A 等于 C=C%A <<= 左移后赋值。例子:C<<=2 等于 C=C<<2 >>= 右移后赋值。例子:C>>=2 等于 C=C>>2 &= 按位与后赋值。例子:C&=2 等于 C=C&2 |= 按位或后赋值。例子:C|=2 等于 C=C|2 ^= 按位异或后赋值。例子:C^=2 等于 C=C^2 func main() { var num1 int = 10 var num2 int = 20 num1 += num2 fmt.Println(num1) // 返回值:30 // 在不使用中间变量的方式,实现a,b两个变量的值相关转换,即a=200,b=100 var a int = 100 var b int = 200 fmt.Println(a) // 返回值:100 fmt.Println(b) // 返回值:200 a = a+b // a=a+b b = a-b // a-b == (a+b)-b=a,此时b=a a = a-b // a-b == (a+b)-a=b,此时a=b fmt.Println(a) // 返回值:200 fmt.Println(b) // 返回值:100 }
十一、fmt 标准库
11.1、获取用户输入的值:
1、fmt.Scan 从标准输入中扫描用户输入的数据,将以空白符分隔的数据分别存入指定的参数。
// fmt.Scan从标准输入中扫描用户输入的数据,将以空白符分隔的数据分别存入指定的参数。 func main() { var ( name string age int married bool ) fmt.Scan(&name, &age, &married) fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married) } //手动输入:szq //手动输入:18 //手动输入:true //返回结果:扫描结果 name:szq age:18 married:true
2、fmt.Scanln 遇到回车键就结束扫描了,这个比较常用。
// fmt.Scanln 遇到回车就结束扫描了,这个比较常用。 func main() { var ( name string age int married bool ) fmt.Scanln(&name, &age, &married) fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married) } //手动输入:szq 18 true (空格作为分隔符) //返回结果:扫描结果 name:szq age:18 married:true
3、fmt.Scanf 不同于fmt.Scan简单的以空格作为输入数据的分隔符,fmt.Scanf为输入数据指定了具体的输入内容格式,只有按照格式输入数据才会被扫描并存入对应变量。
// fmt.Scanf 不同于fmt.Scan简单的以空格作为输入数据的分隔符,fmt.Scanf为输入数据指定了具体的输入内容格式,只有按照格式输入数据才会被扫描并存入对应变量。 func main() { var ( name string age int married bool ) fmt.Scanf("%s %d %t", &name, &age, &married) fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married) }
11.2、通用占位符
占位符 说明 %v 值的默认格式表示 %+v 类似%v,但输出结构体时会添加字段名 %#v 值的Go语法表示 %T 打印值的类型 %% 百分号 func main() { fmt.Printf("%v\n", 100) // 100 fmt.Printf("%v\n", false) // false o := struct{ name string }{"小王子"} fmt.Printf("%v\n", o) // {小王子} fmt.Printf("%#v\n", o) //struct { name string }{name:"小王子"} fmt.Printf("%T\n", o) //struct { name string } fmt.Printf("100%%\n") //100% }
十二、标识符的命名规范
12.1、系统保留关键字
12.2、标识符命名
包名:尽量将package的名称和目录名称保持一致,包名不要和标准库的包名冲突。
变量名,函数名,常量名首字母大写,则可以被其他的包访问,首字母小写,则只能在本包中使用。
// main.go 文件
package main
import (
"Study/go002/module"
"fmt"
)
func main() {
fmt.Println(module.MyName) // 返回值 "sudada"
}
// module.go 文件
package module
var MyName string = "sudada"
十二、引号
12.1、单引号 '' (单个字符,使用单引号)
单引号表示 rune(int32) 类型,单引号里面是单个字符,单引号里面不能写多个字符。单个字符对应的值为该字符的 ASCII 值。
func main() { a1 := 'a' b1 := '1' c1 := '苏' fmt.Println(a1) // 返回值:97 fmt.Println(b1) // 返回值:49 fmt.Println(c1) // 返回值:33487 fmt.Printf("%T\n",a1) // 返回值:int32 fmt.Printf("%T\n",b1) // 返回值:int32 fmt.Printf("%T\n",c1) // 返回值:int32 }
例子2:接收单个字符串时
func main() { var str1 int32 str1 = '1' fmt.Println(str1) // 返回值:45 fmt.Printf("%T\n",str1) // 返回值:int32 var str2 rune str2 = '-' fmt.Println(str2) // 返回值:97 fmt.Printf("%T\n",str2) // 返回值:int32 var str3 byte str3 = 'a' fmt.Println(str3) // 返回值:42 fmt.Printf("%T\n",str3) // 返回值:uint8 }
12.2、双引号 "" (多个字符,使用双引号)
单引号表示string类型
func main() { a1 := "A" b1 := "1" c1 := "王" fmt.Println(a1) // 返回值:A fmt.Println(b1) // 返回值:1 fmt.Println(c1) // 返回值:王 fmt.Printf("%T\n",a1) // 返回值:string fmt.Printf("%T\n",b1) // 返回值:string fmt.Printf("%T\n",c1) // 返回值:string }
12.3、反引号``
func main() { a := `Hello World xxx xxx` fmt.Println(a) } // Hello World // xxx // xxx
十三、go mod 说明
下载包:go get github.com/gin-gonic/gin
下载最新版本包:go get -u github.com/gin-gonic/gin
下载指定版本包:go get github.com/example/package@latest
步骤1(初始化 Go Modules):go mod init your_module_name,这将创建一个 go.mod 文件,记录你的项目的模块信息和当前依赖关系;
步骤2(复制依赖包到vendor目录):"go mod vendor" 会将项目的所有包复制到vendor目录中。这包括go.mod文件中声明的依赖包;
步骤3(go mod download):会根据当前项目的go.mod文件,下载并安装所有依赖包;
13.1、go.mod文件说明(Go项目模块的配置文件,用于管理项目的依赖关系和版本信息)
1.模块声明:每个Go模块的go.mod文件的第一行通常包含模块声明,指定模块的路径和版本。例如:module example.com/myproject
2.依赖声明:在go.mod文件中,你会看到列出了项目依赖的其他模块以及它们的版本信息。例如:require (github.com/gin-gonic/gin v1.7.4),这表示项目依赖于 github.com/gin-gonic/gin 模块的版本 v1.7.4。
3.更新模块版本:你可以使用 go get 命令来更新模块的版本。例如:go get github.com/gin-gonic/gin@latest,这会将 github.com/gin-gonic/gin 模块更新到最新版本。
4.go.mod文件:是"Go Modules"的核心,它使得Go项目的依赖管理更加灵活和精确。在创建新的Go项目时,"Go Modules"会自动生成go.mod文件,而在使用其他人的项目时,你可以使用 go get 等命令来处理依赖关系。13.2、"go mod download"命令说明:(会根据当前项目的go.mod文件,下载并安装所有依赖包)
1.指定版本下载:如果go.mod文件中指定了特定的依赖版本,"go mod download" 将下载这些指定版本的依赖项。这确保了项目在不同环境中使用相同的依赖版本。
2.更新go.sum文件:与"go get 不同,"go mod download" 不会更改go.mod文件中的版本信息,但会更新go.sum文件。这是因为"go mod download"主要用于下载依赖项,而不是更新它们的版本。
3.并发下载:"go mod download"会并发地下载多个依赖项,从而提高下载速度。它利用"Go Modules"的并发性,从各个源同时下载依赖项。
4.离线下载:如果你的项目处于离线状态,"go mod download" 会尝试使用本地缓存的模块信息,而不会尝试从网络上下载。这对于在没有网络连接的环境中构建项目很有用。13.3、"go mod vendor"命令说明(将项目的依赖包复制到项目的vendor目录下。vendor目录是一个本地的依赖包存储目录)
1.创建vendor目录:如果项目中没有vendor目录,"go mod vendor" 将会创建一个。如果已经存在,则会使用已有的vendor目录。
2.复制依赖包到vendor目录:"go mod vendor" 会将项目的所有包复制到vendor目录中。这包括go.mod文件中声明的依赖包。
3.使用本地副本:一旦vendor目录中存在了依赖包,Go编译器将优先使用这些本地副本,而不是从$GOPATH或者模块缓存中下载。
4.更新 vendor 目录:如果go.mod文件中的依赖关系发生变化,你可以运行 "go mod vendor" 以更新 vendor 目录中的本地副本。13.4、"go get"命令说明(用于下载并安装Go语言的包,默认情况下,"go get"将包安装到$GOPATH目录下)
1.获取并安装包:"go get"主要用于获取并安装指定的包。你可以通过指定包的导入路径来下载包,例如:go get github.com/example/package,这将下载并安装 github.com/example/package 包及其依赖项。(如果没有指定版本,"go get"将安装包的最新版本)
2.安装特定版本:你可以通过在包的导入路径后面加上特定的版本信息,来下载并安装特定版本的包。例如:go get github.com/example/package@v1.2.3,这将安装 github.com/example/package 的 v1.2.3 版本。
3.在Go Modules的项目中,"go get"不会修改go.mod文件,而是会将依赖项下载到模块缓存中。如果你想更新go.mod文件,你可以使用"go get"后面跟上包的导入路径,例如:go get github.com/example/package@latest,这会更新 go.mod 文件中的依赖版本。13.5、GOPATH:单一全局工作空间
GOPATH 是一个环境变量,指定了一个全局的工作空间目录,包含了所有的 Go 项目。默认情况下,它包含了三个子目录:bin(可执行文件)、pkg(编译后的包文件)、src(源代码)。
1.依赖管理:以前,Go 使用 GOPATH 来管理项目的依赖关系。当你使用 go get 命令时,它会下载和安装依赖项到 GOPATH 下。
2.导入路径:依赖包的导入路径通常是相对于 GOPATH/src 的路径。
3.全局共享:所有的 Go 项目共享相同的 GOPATH,这可能导致包版本冲突和不同项目之间的干扰。13.6、Go Modules:项目级别的依赖管理
Go Modules 是一种基于项目的依赖管理方式。每个项目都可以有自己的依赖关系,不再依赖于全局的 GOPATH。
1.go.mod 文件:Go Modules 使用 go.mod 文件来记录项目的依赖关系。go.mod 文件包含了项目的模块信息、依赖包和版本信息。
2.导入路径:Go Modules 不再依赖于 GOPATH,导入路径可以是绝对路径或者相对路径。
3.版本管理:Go Modules 使用语义版本(SemVer)来管理依赖项的版本。每个项目都可以指定自己的依赖版本,避免了全局共享的问题。
4.局部缓存:Go Modules 引入了一个局部缓存(module cache)来存储下载的依赖项,减少了对全局空间的依赖。
5.命令行工具:go mod 是 Go Modules 的命令行工具,用于初始化模块、添加或移除依赖项、更新依赖项等。
在实际开发中,推荐使用 Go Modules 来管理项目的依赖关系,因为它提供了更灵活、更可重复、更清晰的依赖管理方式,同时避免了 GOPATH 的一些限制和问题。13.7、Go Modules使用介绍:
1.进入项目目录:打开终端,进入你的 Go 项目的根目录。
2.初始化 Go Modules:go mod init your_module_name,这将创建一个 go.mod 文件,记录你的项目的模块信息和当前依赖关系。
3.使用 go get 命令添加新的依赖包,例如:go get github.com/example/package@v1.2.3,安装Gin框架:go get github.com/gin-gonic/gin
4.自动更新 go.mod:每次运行 go get,go.mod 文件都会被自动更新,记录新的依赖项和版本信息。
5.查看当前项目的依赖项:go list -m all,这将列出当前项目的所有依赖项及其版本信息。
6.如果你想更新依赖项到最新版本,可以运行:go get -u,或者,你可以直接指定某个依赖项的新版本:go get github.com/example/package@latest
7.如果你想移除一个依赖项,可以运行:go get -u github.com/example/package@none,这会将该依赖项标记为不使用。
8.运行项目:使用 go run 命令运行你的项目:go run .
9.构建可执行文件:使用 go build 命令构建可执行文件
10.重要命令:
go mod tidy:清理 go.mod 文件,移除不再使用的依赖项。
go mod verify:校验依赖项的哈希值,确保它们没有被篡改。
go mod download:下载项目的所有依赖项到本地缓存。