[Go语言]基础介绍
Posted jiangwei0512
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Go语言]基础介绍相关的知识,希望对你有一定的参考价值。
Go语言编程环境
Windows下直接下载安装包,这里在https://studygolang.com/dl下载到的go1.17.windows-amd64.msi。安装完成之后可以通过go version
查看:
PS F:\\Gitee\\go\\Code\\Basic> go version
go version go1.17 windows/amd64
还可以查看go
的基本使用方式:
PS F:\\Gitee\\go\\Code\\Basic> go
Go is a tool for managing Go source code.
Usage:
go <command> [arguments]
The commands are:
bug start a bug report
build compile packages and dependencies
clean remove object files and cached files
doc show documentation for package or symbol
env print Go environment information
fix update packages to use new APIs
fmt gofmt (reformat) package sources
generate generate Go files by processing source
get add dependencies to current module and install them
install compile and install packages and dependencies
list list packages or modules
mod module maintenance
run compile and run Go program
test test packages
tool run specified go tool
version print Go version
vet report likely mistakes in packages
Use "go help <command>" for more information about a command.
Additional help topics:
buildconstraint build constraints
buildmode build modes
c calling between Go and C
cache build and test caching
environment environment variables
filetype file types
go.mod the go.mod file
gopath GOPATH environment variable
gopath-get legacy GOPATH go get
goproxy module proxy protocol
importpath import path syntax
modules modules, module versions, and more
module-get module-aware go get
module-auth module authentication using go.sum
packages package lists and patterns
private configuration for downloading non-public code
testflag testing flags
testfunc testing functions
vcs controlling version control with GOVCS
Use "go help <topic>" for more information about that topic.
下面是一个Go语言代码示例:
package main
import "fmt"
func main() {
fmt.Printf("Hello World\\n")
}
编译和运行:
PS F:\\Gitee\\go\\Code\\Basic> go build .\\helloworld.go
PS F:\\Gitee\\go\\Code\\Basic> dir
目录: F:\\Gitee\\go\\Code\\Basic
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2021/8/18 16:06 1937408 helloworld.exe
-a---- 2021/8/18 16:02 78 helloworld.go
PS F:\\Gitee\\go\\Code\\Basic> .\\helloworld.exe
Hello World
到这里,Go语言的基本编程环境已经基本可以使用。
VS Code和插件安装
使用VS Code来编辑和调试Go语言代码,其它都没有问题,但在安装插件之后会一直报错(VS Code需要打开go文件之后才会提示安装额外工具,此时点击安装之后会提示失败),原因是它依赖于一些额外的工具,而这些工具无法下载,需要使用代理。这里通过go env
参数设置代码:
go env -w GOPROXY=https://goproxy.io,direct
之后重启VS Code,再次提示时选择全部安装就能够成功:
Tools environment: GOPATH=C:\\Users\\Administrator\\go
Installing 10 tools at C:\\Users\\Administrator\\go\\bin in module mode.
gopkgs
go-outline
gotests
gomodifytags
impl
goplay
dlv
dlv-dap
staticcheck
gopls
Installing github.com/uudashr/gopkgs/v2/cmd/gopkgs (C:\\Users\\Administrator\\go\\bin\\gopkgs.exe) SUCCEEDED
Installing github.com/ramya-rao-a/go-outline (C:\\Users\\Administrator\\go\\bin\\go-outline.exe) SUCCEEDED
Installing github.com/cweill/gotests/gotests (C:\\Users\\Administrator\\go\\bin\\gotests.exe) SUCCEEDED
Installing github.com/fatih/gomodifytags (C:\\Users\\Administrator\\go\\bin\\gomodifytags.exe) SUCCEEDED
Installing github.com/josharian/impl (C:\\Users\\Administrator\\go\\bin\\impl.exe) SUCCEEDED
Installing github.com/haya14busa/goplay/cmd/goplay (C:\\Users\\Administrator\\go\\bin\\goplay.exe) SUCCEEDED
Installing github.com/go-delve/delve/cmd/dlv (C:\\Users\\Administrator\\go\\bin\\dlv.exe) SUCCEEDED
Installing github.com/go-delve/delve/cmd/dlv@f95340ae1bf9 (C:\\Users\\Administrator\\go\\bin\\dlv-dap.exe) SUCCEEDED
Installing honnef.co/go/tools/cmd/staticcheck (C:\\Users\\Administrator\\go\\bin\\staticcheck.exe) SUCCEEDED
Installing golang.org/x/tools/gopls (C:\\Users\\Administrator\\go\\bin\\gopls.exe) SUCCEEDED
All tools successfully installed. You are ready to Go :).
下载到的文件位于C:\\Users\\Administrator\\go。之后在代码目录下增加launch.json文件:
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${file}",
"env": {
"GOPATH": "C:/Users/Administrator/go",
"GOROOT": "D:/Program Files/Go"
},
"args": [],
}
]
}
其中的GOPATH
和GOROOT
需要根据实际情况配置,可以通过go env
查看,之后就可以通过按F5来编译和使用了,下面是执行helloworld.go代码的结果:
Starting: C:\\Users\\Administrator\\go\\bin\\dlv-dap.exe dap --listen=127.0.0.1:54909
DAP server listening at: 127.0.0.1:54909
Hello World
Process 12460 has exited with status 0
Detaching
dlv dap (15060) exited with code: 0
fmt
学习代码过程中需要了解各种语法的演示结果,这个时候就首先需要掌握如何显示结果,这就需要知道打印方式。
Go语言主要使用fmt
包来处理打印。
首先需要打入包:
import "fmt"
其次介绍几个常用的打印函数:
// Print formats using the default formats for its operands and writes to standard output.
// Spaces are added between operands when neither is a string.
// It returns the number of bytes written and any write error encountered.
func Print(a ...interface{}) (n int, err error)
// Println formats using the default formats for its operands and writes to standard output.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
func Println(a ...interface{}) (n int, err error)
// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
func Printf(format string, a ...interface{}) (n int, err error)
格式化输出Printf()
会用到占位符,说明如下:
%v 值的默认格式
%+v 添加字段名(如结构体)
%#v 相应值的Go语法表示
%T 相应值的类型的Go语法表示
%% 字面上的百分号,并非值的占位符
%t true或false
%b 二进制表示
%c 相应Unicode码点所表示的字符
%d 十进制表示
%o 八进制表示
%q 单引号围绕的字符字面值,由Go语法安全地转义
%x 十六进制表示,字母形式为小写a-f
%X 十六进制表示,字母形式为大写A-F
%U Unicode格式:U+1234,等同于"U+%04X"
%b 无小数部分的,指数为二的幂的科学计数法,与 strconv.FormatFloat中的 'b' 转换格式一致。例如 -123456p-78
%e 科学计数法,例如-1234.456e+78
%E 科学计数法,例如-1234.456E+78
%f 有小数点而无指数,例如 123.456
%g 根据情况选择%e或%f以产生更紧凑的(无末尾的0)输出
%G 根据情况选择%E或%f以产生更紧凑的(无末尾的0)输出
%s 字符串或切片的无解译字节
%q 双引号围绕的字符串,由Go语法安全地转义
%x 十六进制,小写字母,每字节两个字符
%X 十六进制,大写字母,每字节两个字符
%p 十六进制表示,前缀0x
从上面的说明可以看出来使用%v
最简单直接,它会对应到其它的类型,比如bool
就对应到%t
,int
就对应到%d。
Go语法基础
关键字
关键字 | 说明 |
---|---|
package | 定义包名 |
import | 导入包名 |
const | 常量声明 |
var | 变量声明 |
func | 函数定义 |
defer | 延迟执行 |
go | 并发语法糖 |
return | 函数返回 |
struct | 定义结构类型 |
interface | 定义接口类型 |
map | 声明或创建map类型 |
chan | 声明或创建通道类型 |
if else | if else 语句关键字 |
for、range、break、continue | for 循环使用的关键字,range 在for 语句中迭代数组、切片、通道和集合 |
switch、select、type、case、default、fallthrouth | switch 和select 语句使用的关键字 |
goto | goto 跳转语句关键字 |
变量
完整声明:
var varName dataType [ = value ]
跟其它语言将类型放在前面的用法有差异,这里类型放在了变量名之后,下面是一些例子:
var a int = 1
var a int = 2 * 3
var b int = a
短类型:
varName := value
:=
声明只能出现在函数内(包括方法内)。
Go编译器会自动进行数据类型判断。
内置数据类型
可以在builtin\\builtin.go找到定义:
// bool is the set of boolean values, true and false.
type bool bool
// true and false are the two untyped boolean values.
const (
true = 0 == 0 // Untyped bool.
false = 0 != 0 // Untyped bool.
)
// uint8 is the set of all unsigned 8-bit integers.
// Range: 0 through 255.
type uint8 uint8
// uint16 is the set of all unsigned 16-bit integers.
// Range: 0 through 65535.
type uint16 uint16
// uint32 is the set of all unsigned 32-bit integers.
// Range: 0 through 4294967295.
type uint32 uint32
// uint64 is the set of all unsigned 64-bit integers.
// Range: 0 through 18446744073709551615.
type uint64 uint64
// int8 is the set of all signed 8-bit integers.
// Range: -128 through 127.
type int8 int8
// int16 is the set of all signed 16-bit integers.
// Range: -32768 through 32767.
type int16 int16
// int32 is the set of all signed 32-bit integers.
// Range: -2147483648 through 2147483647.
type int32 int32
// int64 is the set of all signed 64-bit integers.
// Range: -9223372036854775808 through 9223372036854775807.
type int64 int64
// float32 is the set of all IEEE-754 32-bit floating-point numbers.
type float32 float32
// float64 is the set of all IEEE-754 64-bit floating-point numbers.
type float64 float64
// complex64 is the set of all complex numbers with float32 real and
// imaginary parts.
type complex64 complex64
// complex128 is the set of all complex numbers with float64 real and
// imaginary parts.
type complex128 complex128
// string is the set of all strings of 8-bit bytes, conventionally but not
// necessarily representing UTF-8-encoded text. A string may be empty, but
// not nil. Values of string type are immutable.
type string string
// int is a signed integer type that is at least 32 bits in size. It is a
// distinct type, however, and not an alias for, say, int32.
type int int
// uint is an unsigned integer type that is at least 32 bits in size. It is a
// distinct type, however, and not an alias for, say, uint32.
type uint uint
// uintptr is an integer type that is large enough to hold the bit pattern of
// any pointer.
type uintptr uintptr
// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
// used, by convention, to distinguish byte values from 8-bit unsigned
// integer values.
type byte = uint8
// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.
type rune = int32
// iota is a predeclared identifier representing the untyped integer ordinal
// number of the current const specification in a (usually parenthesized)
// const declaration. It is zero-indexed.
const iota = 0 // Untyped int.
// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type
// Type is here for the purposes of documentation only. It is a stand-in
// for any Go type, but represents the same type for any given function
// invocation.
type Type int
// Type1 is here for the purposes of documentation only. It is a stand-in
// for any Go type, but represents the same type for any given function
// invocation.
type Type1 int
// IntegerType is here for the purposes of documentation only. It is a stand-in
// for any integer type: int, uint, int8 etc.
type IntegerType int
// FloatType is here for the purposes of documentation only. It is a stand-in
// for either float type: float32 or float64.
type FloatType float32
// ComplexType is here for the purposes of documentation only. It is a
// stand-in for either complex type: complex64 or complex128.
type ComplexType complex64
// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
Error() string
}
基本类型说明如下:
- 整型
byte
int
int8
int16
int32
int64
uint
uint8
uint16
uint32
uint64
uintptr
byte
其实就是uint8
。
- 浮点型
float32
float64
浮点数字字面值被自动类型推断为float64
,即var f := 10.0
中,f
的类型是float64
。
由于计算机精度的问题,浮点类型之间不应该用==
和!=
来进行比较。
- 复数
complex64
complex128
complex64
由两个float32
构成,complex128
由两个float64
构成。
复数的示例:
package main
import "fmt"
func main() {
var c complex64 = 2.3 + 4.5i
fmt.Printf("c = %v\\n", c) // c = (2.3+4.5i)
fmt.Printf("real: %v\\n", real(c)) // 2.3
fmt.Printf("imag: %v\\n", imag(c)) // 4.5
}
- 字符和字符串
string
(字符串)rune
(字符)
rune
其实就是int32
。
字符串不包含NULL
字符,这跟c语言里面是不一样的。
字符串的底层实现是一个二元的数据结构,一个是指针指向字符串数组的起点,另一个是长度。
- 错误类型
error
- 布尔
bool
(true
和false
,默认是false
)
package main
import "fmt"
func main() {
var a bool
fmt.Printf("a = %t\\n", a) // a = false
}
常量值
值 | 说明 |
---|---|
ture false | 表示bool类型的两个值,真和假。 |
iota | 常量计数器,用在常量表达式中。 |
nil | 指针/引用类型的变量的默认值是nil。 |
iota
可以看作自增的枚举类型,下面是使用示例:
package main
import "fmt"
func main() {
const x = iota // 0
const y = iota // 还是0
fmt.Printf("x = %d, y = %d\\n", x, y)
const (
a = iota // 0
b = iota // 1
c = 10 // 10, iota为2
d = iota // 所以这里是3
)
fmt.Printf("a = %d, b = %d, c = %d, d = %d\\n", a, b, c, d)
const (
x0 = iota // 0
x1 // 1
x2 // 2
)
fmt.Printf("x0 = %d, x1 = %d, x2 = %d\\n", x0, x1, x2)
}
空白
就是下划线(_
),可作为占位符,比如下面的例子:
package main
import "fmt"
func two_return_value() (int, int) {
return 1, 2
}
func main() {
// a := two_return_value() // 错误
_, a := two_return_value()
fmt.Printf("a = %d\\n", a)
}
注释部分不能使用,需要改成它下面那行的样子。
复合数据类型
指针
* pointerType
指针类型使用*后接其指向的类型名。
指针示例:
package main
import "fmt"
func main() {
var a int = 1;
var p *int = &a
fmt.Printf("p = %v, *p = %v\\n", p, *p) // p = 0xc0000140a8, *p = 1
}
指针也有解引用,即这里的*p
。
Go语言中没有->
,访问结构体成员还是.
。
Go语言不支持指针操作,比如上例中没有p++
这种操作。Go语言支持垃圾回收,而支持操作会给垃圾回收带来不便,所以在语言层面上禁止了。
Go编译器支持“栈逃逸”机制,可以将局部变量的空间分配到堆上,下面是一个示例:
package main
import "fmt"
func sum (a int, b int) *int {
sum := a + b
return &sum // 不糊报错,sum会被分配到堆上
}
func main() {
a := sum(1, 2)
fmt.Printf("sum = %v\\n", *a)
}
sum()
函数中将局部变量的指针返回了,在c语言中是会有问题的,因为sum
的值在函数栈上,推出函数之后其值是不可知的,但是在Go语言中可以通过“栈逃逸”机制,使得sum
的值被分配到堆中保留下来。
数组
[n] elementType
数组类型使用[n]
后跟数组元素类型来表示,n
表示数组元素的个数,n
可以使...
,表示其长度有初始化的成员个数来决定。
数组示例:
package main
import "fmt"
func main() {
var arr1 [2]int; // 有2个int类型元素的数组,元素值默认是0
arr2 := [...]int{1, 2} // [...]后面跟字面值量初始化数组,长度也是固定下来的,这里是2
arr3 := [3]int{1, 2} // 长度是3,但是定义了2个,则剩下的是0
arr4 := [...]int{1: 1, 2: 2} // 通过索引来初始化,索引从0开始,所以这里长度是3
fmt.Printf("arr1: %v\\n", arr1)
fmt.Printf("arr2: %v\\n", arr2)
fmt.Printf("arr3: %v\\n", arr3)
fmt.Printf("arr4: %v\\n", arr4)
}
数组是值类型,数组赋值或者作为参数传递给函数,都是值拷贝。下面是一个说明示例:
func double(arr [3]int, size int) {
for i := 0; i < size; i++ {
arr[i] = arr[i] * 2
}
fmt.Printf("arr in doube(): %v\\n", arr)
}
func main() {
arr4 := [...]int{1: 1, 2: 2} // 通过索引来初始化,索引从0开始,所以这里长度是3
fmt.Printf("arr before double(): %v\\n", arr4) // arr before double(): [0 1 2]
double(arr4, len(arr4)) // arr in doube(): [0 2 4]
fmt.Printf("arr after double(): %v\\n", arr4) // arr after double(): [0 1 2]
}
可以看到函数外的值并没有被改变。
数组长度是数组类型的组成部分,[1]int
和[2]int
是两个类型。上面的double()
函数中只能传递[3]int
类型的数据,否则会报错:
cannot use arr1 (type [2]int) as type [3]int in argument to double
遍历数组的两种方式:
for i,v := range arr4 {
fmt.Printf("%d: %d\\n", i, v)
}
len := len(arr4)
for i := 0; i < len; i++ {
fmt.Printf("%d: %d\\n", i, arr4[i])
}
切片
[] elementType
切片类型使用[]
后跟切片元素类型来表示。
切片是一种变长数组。
切片是一种引用类型。
切片示例:
package main
import "fmt"
func main() {
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice1 := arr[:] // 完整切片
slice2 := arr[2:] // 从第三个元素(索引2)开始切
slice3 := arr[2:5] // 切第三个到第5个,注意索引5指定的那个值不包含
slice4 := make([]int, 10) //长度为10,容量为10,元素默认值0
slice5 := make([]int, 10, 15) //长度为10,容量为15,元素默认值0
fmt.Printf("slice1 : %v\\n", slice1) // slice1 : [0 1 2 3 4 5 6 7 8 9]
fmt.Printf("slice2 : %v\\n", slice2) // slice2 : [2 3 4 5 6 7 8 9]
fmt.Printf("slice3 : %v\\n", slice3) // slice3 : [2 3 4]
fmt.Printf("slice4 : %v\\n", slice4) // slice4 : [0 0 0 0 0 0 0 0 0 0]
fmt.Printf("slice5 : %v, len: %v, cap: %v\\n", slice5, len(slice5), cap(slice5)) // slice5 : [0 0 0 0 0 0 0 0 0 0], len: 10, cap: 15
// append(slice5, 1) // 报错:append(slice5, 1) evaluated but not used
slice5 = append(slice5, 1) // append()返回增长之后的切片
fmt.Printf("slice5 : %v\\n", slice5) // slice5 : [0 0 0 0 0 0 0 0 0 0 1]
copy(slice5, slice1) // 以上是关于[Go语言]基础介绍的主要内容,如果未能解决你的问题,请参考以下文章