go语言基础入门(一)
- 变量声明:
- 批量声明变量:
- 变量赋值:
- 声明变量同时为变量赋值
- 可以在变量声明时为其赋值
- go中赋值时的编译器会自动根据等号右侧的数据类型自动推导变量的类型
- 使用 := 进行赋值
- 匿名变量
- 常量
- 常量计数器iota
- 1. 使用场景
- 2. 基本用法
- 3. 简化语法
- 4. 自定义增量
- 5. 复杂使用
- go的类似枚举
- 使用 const 和 iota 定义枚举
- 使用 map 实现枚举
- 附加
- Galang(二) 基本数据类型
- 字符串
- 字符串转义符
- 多行字符串
- 常用字符串操作
- byte 和 rune 类型
- 修改字符串
- 类型转换
- 基本语法
- 流程控制
- 1. 条件语句
- if 语句
- switch 语句
- 2. 循环语句
- 基本的 for 循环
- for 循环与条件
- 无限循环
- for range 循环 用于遍历数组、切片、字符串、映射(map)等数据结构。
- 3. 跳转语句
- break 语句
- continue 语句
- goto 语句
变量声明:
变量的声明以 var 关键字开头,后面是变量名,最后是变量的类型,在java中一般使用分号结尾,go则写不写都行,一般不写
var 变量名 变量的类型
var id int
var name string
批量声明变量:
使用 var( ) 括号中 写 变量名 变量的类型
var (
变量名 变量的类型
变量名 变量的类型
变量名 变量的类型
)
var (
id int
name string
)
变量赋值:
go中的变量在声明时会自动初始化,与数字相关的变量默认为 0 ,字符串默认为 “” ,布尔值默认是 false ;切片,函数和指针默认是 nil (nil是go中的空)
声明变量同时为变量赋值
var 变量名 类型 = 值
var id int = 1
var name string = "张三"
可以在变量声明时为其赋值
//多个变量以逗号分隔,等号后的值按照先后顺序赋值
var id ,name = 1 , "张三"
var (
id int = 1
name string = "张三"
)
go中赋值时的编译器会自动根据等号右侧的数据类型自动推导变量的类型
//可以省略变量类型
var (
id = 1
name = "张三"
)
使用 := 进行赋值
还可以使用简写 := 方式声明变量并初始化 这种方法只能在函数内部使用
:=是一个简短声明符(short variable declaration operator),用于在声明变量时简化语法。它允许程序员在声明变量的同时进行初始化。
使用:=声明的变量的作用域是局部的,也就是说,在函数内部使用:=声明的变量只能在该函数内部访问。如果在函数外部使用该符号,会导致编译错误。
:=只能用于声明新变量。如果变量已经被声明,就不能再使用:=方式来赋值,必须使用=运算符。
可以在同一行中使用:=来同时声明多个变量
func main() {
id := 10
name := 200
fmt.Println(m, n)//将id name在控制台输出
}
匿名变量
匿名变量使用 下划线 _ 来表示 ,作用是可以忽略某个值,
可以用来占位 ,此变量不占用命名空间,同时也不会为其分配内存
//t1 函数返回两个int 类型的值
func t1() (int, int) {
return 1, 2
}
func main() {
i, _ := t1()//函数返回的 2 被忽略
_, j := t1()//函数返回的 1 被忽略
fmt.Println(i, j) //输出 1,2
}
在for循环中使用
在迭代的过程中,如果只关心索引或值中的一个部分,可以使用匿名变量。这使得代码更加简洁。
示例:
package main
import "fmt"
func main() {
pairs := []struct {
x, y int
}{
{1, 2},
{3, 4},
{5, 6},
}
for _, v := range pairs {
fmt.Println(v.x) // 只使用x,忽略y
}
}
常量
常量是程序中不可改变的值。常量在声明后不能被重新赋值。
使用const关键字声明常量:
const Pi = 3.14
类型推断:常量可以在声明时指定类型,也可以省略,编译器会根据值自动推断。
const (
e = 2.71828 // 无类型常量
c int = 299792458 // 指定类型常量
)
作用域:
常量的作用域和变量相似,可以是局部的或包级别的。
示例:
package main
import "fmt"
const Pi = 3.14 // 声明常量
func main() {
fmt.Println("Pi:", Pi)
// Pi = 3.14159 // 这将导致编译错误,因为常量不能被修改
}
| 特性 | 变量 | 常量 |
|----------------|--------------------------|---------------------------|
| 可变性 | 可以被修改 | 不可被修改 |
| 声明关键字 | var 或简短声明符 := | const |
| 声明时类型 | 可选 | 可选 |
| 内存使用 | 占用内存 | 编译时确定,无需占用运行时内存 |
| 作用域 | 局部或包级别 | 局部或包级别 |
常量计数器iota
在Go语言中,iota是一个预定义的标识符,用于简化常量的创建,尤其是在需要一系列相关常量时。
iota的值在每个常量声明块中自动递增,从0开始。
1. 使用场景
iota通常用于定义一组具有相关性的常量,例如枚举值、位掩码等。
2. 基本用法
在一个常量声明中,每个常量的iota值会从0开始,并在每行中自动递增1。
package main
import "fmt"
const (
A = iota // 0
B = iota // 1
C = iota // 2
)
func main() {
fmt.Println(A, B, C) // 输出: 0 1 2
}
3. 简化语法
在同一个常量声明块中,可以省略iota,它仍然会正确递增。
package main
import "fmt"
const (
X = iota // 0
Y // 1,自动从上一个常量继承iota值
Z // 2
)
func main() {
fmt.Println(X, Y, Z) // 输出: 0 1 2
}
4. 自定义增量
可以在常量声明中使用算术运算与iota结合,创建具有特定增量的常量。例如,如果希望常量的值是2的倍数,可以这样做:
package main
import "fmt"
const (
_ = iota // 忽略第一个值(0)
Two = iota * 2 // 2
Four = iota * 2 // 4
Six = iota * 2 // 6
)
func main() {
fmt.Println(Two, Four, Six) // 输出: 2 4 6
}
5. 复杂使用
iota还可以与位移、位运算等结合使用,在需要创建位掩码时非常方便。
package main
import "fmt"
const (
Flag1 = 1 << iota // 1 << 0,值为1
Flag2 // 1 << 1,值为2
Flag3 // 1 << 2,值为4
Flag4 // 1 << 3,值为8
)
func main() {
fmt.Println(Flag1, Flag2, Flag3, Flag4) // 输出: 1 2 4 8
}
go的类似枚举
在 Go 1.13 及更高版本中,虽然没有引入传统意义上的枚举类型,但可以通过使用 const 和 iota 来实现类似的功能,
并且可以通过 string 类型的方法来增强枚举的可读性和可维护性。
使用 const 和 iota 定义枚举
在这个例子中,我们定义了一个 Weekday 类型,并使用 iota 来生成枚举值。
然后,我们为 Weekday 类型实现了 String 方法,这样在打印枚举值时,会输出对应的字符串名称,而不是整数值。
package main
import "fmt"
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
func (w Weekday) String() string {
return [...]string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}[w]
}
func main() {
fmt.Println(Sunday) // 输出: Sunday
fmt.Println(Monday) // 输出: Monday
fmt.Println(Tuesday) // 输出: Tuesday
fmt.Println(Wednesday) // 输出: Wednesday
fmt.Println(Thursday) // 输出: Thursday
fmt.Println(Friday) // 输出: Friday
fmt.Println(Saturday) // 输出: Saturday
}
使用 map 实现枚举
另一种方法是使用 map 来实现枚举,这样可以更灵活地处理枚举值和名称之间的映射。
package main
import "fmt"
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
var weekdayNames = map[Weekday]string{
Sunday: "Sunday",
Monday: "Monday",
Tuesday: "Tuesday",
Wednesday: "Wednesday",
Thursday: "Thursday",
Friday: "Friday",
Saturday: "Saturday",
}
func (w Weekday) String() string {
return weekdayNames[w]
}
func main() {
fmt.Println(Sunday) // 输出: Sunday
fmt.Println(Monday) // 输出: Monday
fmt.Println(Tuesday) // 输出: Tuesday
fmt.Println(Wednesday) // 输出: Wednesday
fmt.Println(Thursday) // 输出: Thursday
fmt.Println(Friday) // 输出: Friday
fmt.Println(Saturday) // 输出: Saturday
}
附加
2. 布尔类型
类型:bool
常量:true和false,分别为0 == 0和0 != 0的值。
3. 整数类型
无符号整数:
uint8:范围0至255。
uint16:范围0至65535。
uint32:范围0至4294967295。
uint64:范围0至18446744073709551615。
带符号整数:
int8:范围-128至127。
int16:范围-32768至32767。
int32:范围-2147483648至2147483647。
int64:范围-9223372036854775808至9223372036854775807。
int:至少32位的带符号整数,不是int32的别名。
uint:至少32位的无符号整数,不是uint32的别名。
4. 浮点数和复数类型
浮点数:
float32和float64分别为IEEE 754格式的32位和64位浮点数。
复数:
complex64和complex128分别为具有float32和float64实部和虚部的复数。
5. 字符串和字节
类型:
string:表示8位字节字符串,通常表示UTF-8编码文本。
byte:是uint8的别名,通常用于表示字节值。
rune:是int32的别名,用于表示字符值。
6. 预声明标识符
nil:表示指针、通道、函数、接口、映射或切片类型的零值。
iota:表示当前常量声明中的未类型化整数序号,从0开始递增。
any:是interface{}的别名,表示可以接受任何类型的空接口。
comparable:一个接口,所有可比较类型(布尔、数字、字符串等)都实现该接口,但它只能作为类型参数的约束,而不能作为变量的类型。
7. 内置函数
基本操作:
append:将元素追加到切片末尾。
copy:从源切片复制元素到目标切片。
delete:从映射中删除指定键的元素。
len:返回值的长度。
cap:返回切片或通道的容量。
内存管理:
make:用于分配和初始化切片、映射或通道。
new:分配内存并返回指向新分配零值的指针。
数学操作:
max:返回一组值中的最大值。
min:返回一组值中的最小值。
complex、real、imag:用于复数的创建和获取实部、虚部。
通道操作:
close:关闭通道。
clear:清空映射和切片。
错误处理:
panic:停止当前goroutine的正常执行。
recover:恢复正在恐慌的goroutine的正常执行。
打印输出:
print和println:将数据格式化并写入标准错误。
8. 错误接口
error:表示错误条件的常规接口,nil值表示没有错误。
Galang(二) 基本数据类型
字符串
Go语言中的字符串以原生数据类型出现,使用字符串就像使用其他原生数据类型(int、bool、float32、float64 等)一样。 Go 语言里的字符串的内部实现使用UTF-8
编码。 字符串的值为双引号(")
中的内容,可以在Go语言的源码中直接添加非ASCII码字符
s1 := "hello Word"
字符串转义符
\r | 回车符(返回行首) |
---|---|
\n | 换行符(直接跳到下一行的同列位置) |
\t | 制表符 |
\’ | 单引号 |
\” | 双引号 |
\ | 反斜杠 |
多行字符串
Go语言中要定义一个多行字符串时,就必须使用反引号
字符
s1 := `第一行
第二行
第三行
`
fmt.Println(s1)
常用字符串操作
方法 | 作用 |
---|---|
len(str) | 求长度 |
+或fmt.Sprintf | 拼接字符型 |
strings.Split | 分割 |
strings.contains | 判断是否包含 |
strings.HasPrefix strings.HasSuffix | 前缀 后缀判断 |
strings.Index() strings.LastIndex() | 子串出现的位置 |
strings.Join(a[]string, sep string) | join操作 |
package main
import (
"fmt"
"strings"
)
func main() {
// 定义字符串
str := "Hello, World! Welcome to Go programming."
// 1. 求长度
length := len(str)
fmt.Println("字符串长度:", length)
// 2. 拼接字符型
str2 := " Enjoy learning!"
concatenated := str + str2
fmt.Println("拼接后的字符串:", concatenated)
// 3. 分割
// 注意:分割后的部分是字符串数组,不是切片
parts := strings.Split(str, " ")
fmt.Println("分割后的部分:", parts[0], parts[1], parts[2])
// 4. 判断是否包含
containsHello := strings.Contains(str, "Hello")
fmt.Println("包含 'Hello'?", containsHello)
// 5. 前缀和后缀判断
hasPrefix := strings.HasPrefix(str, "Hello")
hasSuffix := strings.HasSuffix(str, "programming.")
fmt.Println("以 'Hello' 开头?", hasPrefix)
fmt.Println("以 'programming.' 结尾?", hasSuffix)
// 6. 子串出现的位置
index := strings.Index(str, "World")
lastIndex := strings.LastIndex(str, "o")
fmt.Println("'World' 出现的位置:", index)
fmt.Println("'o' 最后出现的位置:", lastIndex)
// 7. join操作
words := []string{"Go", "is", "great!"}
joined := strings.Join(words, " ")
fmt.Println("连接后的字符串:", joined)
// 8. 替换
replaced := strings.Replace(str, "World", "Gopher", 1)
fmt.Println("替换后的字符串:", replaced)
// 9. 大小写转换
upper := strings.ToUpper(str)
lower := strings.ToLower(str)
fmt.Println("全大写:", upper)
fmt.Println("全小写:", lower)
// 10. 去掉空白
strWithSpaces := " Hello, World! "
trimmed := strings.TrimSpace(strWithSpaces)
fmt.Println("去掉空白后的字符串:", trimmed)
// 11. 判断是否为空
if str == "" {
fmt.Println("字符串是空的")
} else {
fmt.Println("字符串不是空的")
}
// 12. 格式化字符串
name := "Go"
version := 1.18
formatted := fmt.Sprintf("%s programming language version %.2f", name, version)
fmt.Println("格式化字符串:", formatted)
// 13. 多个替换
replacer := strings.NewReplacer("Hello", "Hi", "World", "Gopher")
newStr := replacer.Replace(str)
fmt.Println("多个替换后的字符串:", newStr)
}
byte 和 rune 类型
组成每个字符串的元素叫做“字符”,可以通过遍历或者单个获取字符串元素获得字符。
字符用单引号(’)包裹起来
byte 适合用于处理ASCII字符及二进制数据,常用于文件和网络数据的操作。
rune 更适合处理包含Unicode字符的字符串,能够处理各种语言的字符,是进行国际化开发时不可或缺的类型。
var a = '中'
var b = 'x'
Go 语言的字符有以下两种
-
uint8
类型,或者叫 byte 型,代表了ASCII码
的一个字符。 -
rune
类型,代表一个UTF-8字符
。当需要处理中文、日文或者其他复合字符时,则需要用到
rune
类型。rune
类型实际是一个int32
// 遍历字符串
func traversalString() {
s := "hello世界"
for i := 0; i < len(s); i++ { //byte
fmt.Printf("%v(%c) ", s[i], s[i])
}
fmt.Println()
for _, r := range s { //rune
fmt.Printf("%v(%c) ", r, r)
}
fmt.Println()
}
输出:
104(h) 101(e) 108(l) 108(l) 111(o) 230(æ) 178(²) 153() 230(æ) 178(²) 179(³)
104(h) 101(e) 108(l) 108(l) 111(o) 19990(世) 30028(界)
因为UTF8编码下一个中文汉字由3~4个字节组成,所以我们不能简单的按照字节去遍历一个包含中文的字符串,否则就会出现上面输出中第一行的结果
字符串底层是一个byte数组,所以可以和[]byte
类型相互转换。字符串是不能修改的 字符串是由byte字节组成,所以字符串的长度是byte字节的长度。 rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成
修改字符串
要修改字符串,需要先将其转换成[]rune
或[]byte
,完成后再转换为string
。无论哪种转换,都会重新分配内存,并复制字节数组
package main
import (
"fmt"
)
func main() {
// 使用 byte 处理 ASCII 字符
var b byte = 'A'
fmt.Println("byte 类型:", b)
// 使用 rune 处理 Unicode 字符
var r rune = '汉'
fmt.Println("rune 类型:", r)
// 字符串中的字节和字符数
str := "Hello, 世界!"
fmt.Println("字符串的字节数:", len(str))
// 使用 range 遍历字符串中的字符
fmt.Println("字符和对应的 rune值:")
for i, c := range str {
fmt.Printf("索引 %d: 字符 %c, rune 值 %d\n", i, c, c)
}
}
类型转换
在 Go 语言中,类型转换是将一个数据类型的值转换为另一个数据类型的过程。Go 语言提供了安全和明确的类型转换机制,以确保类型的一致性。
基本语法
类型转换的基本语法如下:
newType(expression) 其中 newType 是目标类型,expression 是要转换的值。
基本数值类型的转换
package main
import "fmt"
func main() {
var a int = 10
var b float64 = float64(a) // int 转换为 float64
fmt.Println("int:", a)
fmt.Println("float64:", b)
var c float64 = 3.14
var d int = int(c) // float64 转换为 int(会丢失小数部分)
fmt.Println("float64:", c)
fmt.Println("int:", d)
}
字符与整数的转换
package main
import "fmt"
func main() {
var r rune = 'A' // 字符 'A'
var b byte = byte(r) // rune 转换为 byte
var ascii int = int(b) // byte 转换为 int
fmt.Printf("rune: %c, byte: %d, ascii: %d\n", r, b, ascii) // 输出: rune: A, byte: 65, ascii: 65
}
字符串与字节切片的转换
package main
import "fmt"
func main() {
str := "Hello, Go!"
// 字符串转换为字节切片
byteSlice := []byte(str)
fmt.Println("Byte Slice:", byteSlice)
// 字节切片转换为字符串
newStr := string(byteSlice)
fmt.Println("String:", newStr)
}
接口转换 Go 语言中的类型转换也包括接口类型的转换。可以将实现了某个接口的类型转换为该接口。
package main
import "fmt"
type Animal interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string {
return "Woof!"
}
func main() {
var a Animal // 接口类型
a = Dog{} // 赋值实现了 Animal 接口的 Dog 类型
// 类型断言
if dog, ok := a.(Dog); ok {
fmt.Println("它是狗,叫声:", dog.Speak())
}
}
流程控制
1. 条件语句
Go 中的条件语句主要有 if 和 switch。
if 语句
用来根据条件执行特定的代码块。
package main
import (
"fmt"
)
func main() {
age := 18
if age < 18 {
fmt.Println("未成年人")
} else if age >= 18 && age < 65 {
fmt.Println("成年人")
} else {
fmt.Println("老年人")
}
}
switch 语句
用于多条件判断,它比多个 if 语句更简洁。
package main
import (
"fmt"
)
func main() {
day := 3
switch day {
case 1:
fmt.Println("星期一")
case 2:
fmt.Println("星期二")
case 3:
fmt.Println("星期三")
default:
fmt.Println("其他天")
}
}
一个分支可以有多个值,多个case值中间使用英文逗号分隔。
func testSwitch3() {
switch n := 7; n {
case 1, 3, 5, 7, 9:
fmt.Println("奇数")
case 2, 4, 6, 8:
fmt.Println("偶数")
default:
fmt.Println(n)
}
}
分支还可以使用表达式,这时候switch语句后面不需要再跟判断变量
func switchDemo4() {
age := 30
switch {
case age < 25:
fmt.Println("好好学习吧")
case age > 25 && age < 35:
fmt.Println("好好工作吧")
case age > 60:
fmt.Println("好好享受吧")
default:
fmt.Println("活着真好")
}
}
fallthrough
语法可以执行满足条件的case的下一个case,是为了兼容C语言中的case设计的
func switchDemo5() {
s := "a"
switch {
case s == "a":
fmt.Println("a")
fallthrough
case s == "b":
fmt.Println("b")
case s == "c":
fmt.Println("c")
default:
fmt.Println("...")
}
}
输出: a b
2. 循环语句
Go 语言中提供了 for 循环来实现循环,使用非常灵活。
基本的 for 循环
package main
import (
"fmt"
)
func main() {
for i := 0; i < 5; i++ {
fmt.Println("计数:", i)
}
}
for 循环与条件
也可以使用 for 循环形式的条件判断。
package main
import (
"fmt"
)
func main() {
i := 0
for i < 5 {
fmt.Println("计数:", i)
i++
}
}
无限循环
使用 for 后不加条件,即可形成无限循环。
循环可以通过break、goto、return、panic语句强制退出循环。
package main
import (
"fmt"
)
func main() {
i := 0
for {
if i >= 5 {
break // 使用 break 退出循环
}
fmt.Println("计数:", i)
i++
}
}
for range 循环 用于遍历数组、切片、字符串、映射(map)等数据结构。
基本语法
for range 的基本语法如下:
for index, value := range collection {
// 使用 index 和 value
}
index 是当前元素的索引(对于数组、切片和字符串)。
value 是当前元素的值。
collection 是需要遍历的集合,可以是数组、切片、字符串或映射等。
遍历切片
package main
import (
"fmt"
)
func main() {
names := []string{"Alice", "Bob", "Charlie"}
for index, name := range names {
fmt.Printf("索引: %d, 名称: %s\n", index, name)
}
}
遍历数组
package main
import (
"fmt"
)
func main() {
numbers := [5]int{1, 2, 3, 4, 5}
for index, number := range numbers {
fmt.Printf("索引: %d, 数字: %d\n", index, number)
}
}
遍历字符串 for range 还能用来遍历字符串,每次迭代返回一个字符和它的 Unicode 码点。
package main
import (
"fmt"
)
func main() {
str := "你好, 世界!"
for index, char := range str {
fmt.Printf("索引: %d, 字符: %c\n", index, char)
}
}
遍历映射 (map)
package main
import (
"fmt"
)
func main() {
ages := map[string]int{
"Alice": 25,
"Bob": 30,
"Charlie": 35,
}
for name, age := range ages {
fmt.Printf("%s 的年龄是: %d\n", name, age)
}
}
3. 跳转语句
Go 中的跳转语句包括 break、continue 和 goto。
break 语句
用于跳出循环或 switch 语句。
package main
import (
"fmt"
)
func main() {
for i := 0; i < 10; i++ {
if i == 5 {
break // 当 i 等于 5 时跳出循环
}
fmt.Println("计数:", i)
}
}
continue 语句
用于跳过当前循环的剩余部分,进入下一次循环。
package main
import (
"fmt"
)
func main() {
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue // 跳过偶数
}
fmt.Println("奇数:", i)
}
}
goto 语句
允许程序跳转到指定标签。使用要谨慎,因为可能会导致代码可读性降低。
package main
import (
"fmt"
)
func main() {
i := 0
CountLoop:
fmt.Println("计数:", i)
i++
if i < 5 {
goto CountLoop // 跳转到 CountLoop 标签
}
}