Golang基础编程:基本数据类型与复合数据类型
学习目标
- 掌握Go语言的基本数据类型(整型、浮点型、布尔型、字符串)
- 理解复合数据类型(数组、切片、映射)的使用方法
- 学会使用结构体、指针和接口
- 掌握类型转换和类型断言的技巧
- 理解Go语言的类型系统和内存模型
1. 基本数据类型
1.1 布尔型(bool)
布尔型只有两个值:true和false。
package main
import "fmt"
func main() {
// 布尔型变量声明
var isActive bool = true
var isCompleted bool = false
// 简短声明
isReady := true
// 布尔运算
fmt.Println("与运算:", true && false) // false
fmt.Println("或运算:", true || false) // true
fmt.Println("非运算:", !true) // false
// 条件判断
if isActive && isReady {
fmt.Println("系统已激活且准备就绪")
}
// 类型转换
var b bool
fmt.Printf("零值: %t\n", b) // false
}
1.2 数字类型
Go语言提供了丰富的数字类型:
1.2.1 整型
package main
import "fmt"
func main() {
// 有符号整型
var i8 int8 = 127 // -128 到 127
var i16 int16 = 32767 // -32768 到 32767
var i32 int32 = 2147483647 // -2^31 到 2^31-1
var i64 int64 = 9223372036854775807 // -2^63 到 2^63-1
var i int = 42 // 平台相关,32位系统为int32,64位系统为int64
// 无符号整型
var ui8 uint8 = 255 // 0 到 255 (byte是uint8的别名)
var ui16 uint16 = 65535 // 0 到 65535
var ui32 uint32 = 4294967295 // 0 到 2^32-1
var ui64 uint64 = 18446744073709551615 // 0 到 2^64-1
var ui uint = 42 // 平台相关
// 特殊整型
var b byte = 'A' // byte是uint8的别名
var r rune = '中' // rune是int32的别名,用于表示Unicode字符
fmt.Printf("int8: %d, uint8: %d, rune: %c\n", i8, ui8, r)
// 不同进制的表示
decimal := 100 // 十进制
binary := 0b1010 // 二进制(10)
octal := 0o12 // 八进制(10)
hexadecimal := 0xA // 十六进制(10)
fmt.Printf("十进制: %d, 二进制: %d, 八进制: %d, 十六进制: %d\n",
decimal, binary, octal, hexadecimal)
}
1.2.2 浮点型
package main
import "fmt"
import "math"
func main() {
// 浮点类型
var f32 float32 = 3.14159
var f64 float64 = 3.141592653589793
// 科学计数法
large := 1.23e9 // 1.23 × 10^9
small := 1.23e-5 // 1.23 × 10^-5
fmt.Printf("float32: %.5f, float64: %.15f\n", f32, f64)
fmt.Printf("大数: %e, 小数: %e\n", large, small)
// 浮点数精度问题
fmt.Println("0.1 + 0.2 == 0.3:", 0.1+0.2 == 0.3) // false
// 使用math包
fmt.Println("Pi:", math.Pi)
fmt.Println("E:", math.E)
fmt.Println("Sqrt(16):", math.Sqrt(16))
fmt.Println("Pow(2, 10):", math.Pow(2, 10))
}
1.2.3 复数类型
package main
import "fmt"
import "math/cmplx"
func main() {
// 复数类型
var c1 complex64 = 3 + 4i
var c2 complex128 = 5 - 2i
// 简短声明
c3 := 1 + 2i
// 使用complex函数创建
c4 := complex(3, 4) // 3 + 4i
fmt.Printf("c1: %v, 实部: %f, 虚部: %f\n", c1, real(c1), imag(c1))
fmt.Printf("c2: %v, 模: %f, 幅角: %f\n", c2, cmplx.Abs(c2), cmplx.Phase(c2))
// 复数运算
fmt.Println("c1 + c2:", c1 + complex64(c2))
fmt.Println("c1 * c2:", c1 * complex64(c2))
// 共轭复数
fmt.Println("c1的共轭:", cmplx.Conj(complex128(c1)))
}
1.3 字符串(string)
package main
import (
"fmt"
"strings"
"unicode/utf8"
)
func main() {
// 字符串定义
var s1 string = "Hello, Go!"
s2 := "世界,你好!"
// 字符串长度
fmt.Printf("s1长度: %d, s2长度: %d\n", len(s1), len(s2))
fmt.Printf("s1字符数: %d, s2字符数: %d\n",
len(s1), utf8.RuneCountInString(s2))
// 字符串拼接
s3 := s1 + " " + s2
s4 := fmt.Sprintf("%s %s", s1, s2)
fmt.Println("拼接结果:", s3)
fmt.Println("格式化拼接:", s4)
// 字符串切片(按字节)
fmt.Println("s1[0:5]:", s1[0:5]) // Hello
fmt.Println("s2[0:3]:", s2[0:3]) // 世 (UTF-8编码的前3个字节)
// 字符串遍历
fmt.Println("遍历s1(按字节):")
for i := 0; i < len(s1); i++ {
fmt.Printf("%c ", s1[i])
}
fmt.Println()
fmt.Println("遍历s2(按字符):")
for _, r := range s2 {
fmt.Printf("%c ", r)
}
fmt.Println()
// 常用字符串函数
fmt.Println("包含'Go':", strings.Contains(s1, "Go"))
fmt.Println("前缀'Hello':", strings.HasPrefix(s1, "Hello"))
fmt.Println("后缀'Go!':", strings.HasSuffix(s1, "Go!"))
fmt.Println("替换:", strings.Replace(s1, "Go", "Golang", 1))
fmt.Println("分割:", strings.Split(s1, ", "))
fmt.Println("大小写:", strings.ToUpper(s1), strings.ToLower(s1))
fmt.Println("修剪:", strings.TrimSpace(" Hello "))
// 字符串和字节切片转换
bytes := []byte(s1)
str := string(bytes)
fmt.Printf("字符串转字节: %v\n", bytes)
fmt.Printf("字节转字符串: %s\n", str)
// 字符串和rune切片转换
runes := []rune(s2)
str2 := string(runes)
fmt.Printf("字符串转rune: %v\n", runes)
fmt.Printf("rune转字符串: %s\n", str2)
}
2. 复合数据类型
2.1 数组(Array)
数组是固定长度的同类型元素序列。
package main
import "fmt"
func main() {
// 数组声明
var arr1 [5]int // 声明长度为5的int数组,零值初始化
var arr2 = [5]int{1, 2, 3, 4, 5} // 声明并初始化
arr3 := [5]int{1, 2, 3} // 部分初始化,其余为零值
arr4 := [...]int{1, 2, 3, 4, 5} // 编译器推断长度
fmt.Println("arr1:", arr1)
fmt.Println("arr2:", arr2)
fmt.Println("arr3:", arr3)
fmt.Println("arr4:", arr4)
// 访问和修改数组元素
arr1[0] = 10
arr1[4] = 50
fmt.Println("修改后的arr1:", arr1)
fmt.Println("第一个元素:", arr1[0])
fmt.Println("最后一个元素:", arr1[len(arr1)-1])
// 数组遍历
fmt.Println("数组遍历:")
for i := 0; i < len(arr2); i++ {
fmt.Printf("arr2[%d] = %d\n", i, arr2[i])
}
fmt.Println("range遍历:")
for index, value := range arr2 {
fmt.Printf("索引: %d, 值: %d\n", index, value)
}
// 多维数组
var matrix [3][3]int = [3][3]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
fmt.Println("3x3矩阵:")
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
fmt.Printf("%d ", matrix[i][j])
}
fmt.Println()
}
// 数组比较
arr5 := [3]int{1, 2, 3}
arr6 := [3]int{1, 2, 3}
arr7 := [3]int{1, 2, 4}
fmt.Println("arr5 == arr6:", arr5 == arr6) // true
fmt.Println("arr5 == arr7:", arr5 == arr7) // false
// 数组作为函数参数(值传递)
modifyArray(arr5)
fmt.Println("modifyArray后的arr5:", arr5) // 原数组不变
// 数组指针作为函数参数
modifyArrayPtr(&arr5)
fmt.Println("modifyArrayPtr后的arr5:", arr5) // 原数组被修改
}
func modifyArray(arr [3]int) {
arr[0] = 100
fmt.Println("函数内arr:", arr)
}
func modifyArrayPtr(arr *[3]int) {
arr[0] = 100
fmt.Println("函数内arr:", *arr)
}
2.2 切片(Slice)
切片是动态数组,是Go中最常用的数据结构。
package main
import "fmt"
func main() {
// 切片声明
var s1 []int // 声明nil切片
s2 := []int{} // 空切片
s3 := []int{1, 2, 3, 4, 5} // 初始化切片
s4 := make([]int, 5) // 创建长度为5的切片,零值初始化
s5 := make([]int, 3, 10) // 创建长度为3,容量为10的切片
fmt.Println("s1:", s1, "长度:", len(s1), "容量:", cap(s1))
fmt.Println("s2:", s2, "长度:", len(s2), "容量:", cap(s2))
fmt.Println("s3:", s3, "长度:", len(s3), "容量:", cap(s3))
fmt.Println("s4:", s4, "长度:", len(s4), "容量:", cap(s4))
fmt.Println("s5:", s5, "长度:", len(s5), "容量:", cap(s5))
// 从数组创建切片
arr := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
s6 := arr[2:7] // 包含索引2到6的元素
s7 := arr[:5] // 包含前5个元素
s8 := arr[5:] // 包含从索引5开始的元素
s9 := arr[:] // 包含所有元素
fmt.Println("从数组创建切片:")
fmt.Println("arr:", arr)
fmt.Println("s6[2:7]:", s6)
fmt.Println("s7[:5]:", s7)
fmt.Println("s8[5:]:", s8)
fmt.Println("s9[:]:", s9)
// 切片追加元素
s10 := []int{1, 2, 3}
s10 = append(s10, 4)
s10 = append(s10, 5, 6, 7)
fmt.Println("追加元素:", s10)
// 追加切片
s11 := []int{8, 9, 10}
s10 = append(s10, s11...)
fmt.Println("追加切片:", s10)
// 切片拷贝
src := []int{1, 2, 3, 4, 5}
dst := make([]int, len(src))
copy(dst, src)
fmt.Println("拷贝后的dst:", dst)
// 切片作为函数参数(引用传递)
original := []int{1, 2, 3}
modifySlice(original)
fmt.Println("modifySlice后的original:", original) // 原切片被修改
// 切片的切片
matrix := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
fmt.Println("二维切片:")
for i, row := range matrix {
fmt.Printf("第%d行: %v\n", i+1, row)
}
// 切片排序
numbers := []int{3, 1, 4, 1, 5, 9, 2, 6}
sort.Ints(numbers)
fmt.Println("排序后:", numbers)
// 切片过滤
even := filter(numbers, func(n int) bool {
return n%2 == 0
})
fmt.Println("偶数:", even)
}
func modifySlice(s []int) {
if len(s) > 0 {
s[0] = 100
}
}
func filter(s []int, fn func(int) bool) []int {
var result []int
for _, v := range s {
if fn(v) {
result = append(result, v)
}
}
return result
}
2.3 映射(Map)
映射是无序的键值对集合。
package main
import "fmt"
func main() {
// Map声明
var m1 map[string]int // 声明nil map
m2 := make(map[string]int) // 创建空map
m3 := map[string]int{ // 初始化map
"apple": 5,
"banana": 3,
"orange": 7,
}
fmt.Println("m1:", m1)
fmt.Println("m2:", m2)
fmt.Println("m3:", m3)
// 添加和修改元素
m2["apple"] = 10
m2["banana"] = 20
m2["apple"] = 15 // 修改已存在的键
fmt.Println("添加元素后的m2:", m2)
// 访问元素
value := m2["apple"]
fmt.Println("apple的数量:", value)
// 访问不存在的键
value2, exists := m2["grape"]
if exists {
fmt.Println("grape的数量:", value2)
} else {
fmt.Println("grape不存在")
}
// 删除元素
delete(m2, "banana")
fmt.Println("删除banana后的m2:", m2)
// Map遍历
fmt.Println("Map遍历:")
for key, value := range m3 {
fmt.Printf("%s: %d\n", key, value)
}
// Map长度
fmt.Println("m3的长度:", len(m3))
// 复杂Map
students := map[string]map[string]int{
"张三": {
"数学": 90,
"英语": 85,
"物理": 88,
},
"李四": {
"数学": 95,
"英语": 92,
"物理": 89,
},
}
fmt.Println("学生成绩:")
for name, scores := range students {
fmt.Printf("%s: ", name)
for subject, score := range scores {
fmt.Printf("%s=%d ", subject, score)
}
fmt.Println()
}
// Map作为函数参数(引用传递)
original := map[string]int{"a": 1, "b": 2}
modifyMap(original)
fmt.Println("modifyMap后的original:", original) // 原map被修改
// Map的键类型限制
// 合法的键类型:bool, 数字, string, 指针, channel, 接口, 结构体, 数组
// 不合法的键类型:slice, map, function
// 使用结构体作为键
type Point struct {
X, Y int
}
points := map[Point]string{
{0, 0}: "原点",
{1, 1}: "点(1,1)",
{2, 3}: "点(2,3)",
}
fmt.Println("点映射:")
for point, name := range points {
fmt.Printf("(%d,%d): %s\n", point.X, point.Y, name)
}
}
func modifyMap(m map[string]int) {
m["c"] = 3
m["a"] = 100
}
3. 结构体、指针和接口
3.1 结构体(Struct)
结构体是自定义的复合数据类型。
package main
import "fmt"
// 定义结构体
type Person struct {
Name string
Age int
Email string
private string // 小写字段名表示私有字段
}
// 嵌套结构体
type Address struct {
City string
Country string
ZipCode string
}
type Employee struct {
Person // 匿名字段
ID int
Position string
Salary float64
Address // 匿名字段
}
func main() {
// 结构体声明和初始化
var p1 Person
p1.Name = "张三"
p1.Age = 30
p1.Email = "zhangsan@example.com"
fmt.Println("p1:", p1)
// 字面量初始化
p2 := Person{
Name: "李四",
Age: 25,
Email: "lisi@example.com",
}
fmt.Println("p2:", p2)
// 简短初始化(必须提供所有字段)
p3 := Person{"王五", 35, "wangwu@example.com", "private"}
fmt.Println("p3:", p3)
// 结构体指针
p4 := &Person{
Name: "赵六",
Age: 28,
Email: "zhaoliu@example.com",
}
fmt.Println("p4:", *p4)
fmt.Println("p4.Name:", p4.Name) // 自动解引用
// 使用new创建结构体指针
p5 := new(Person)
p5.Name = "孙七"
p5.Age = 32
fmt.Println("p5:", *p5)
// 嵌套结构体
emp := Employee{
Person: Person{
Name: "陈八",
Age: 40,
Email: "chenba@company.com",
},
ID: 1001,
Position: "高级工程师",
Salary: 15000.50,
Address: Address{
City: "北京",
Country: "中国",
ZipCode: "100000",
},
}
fmt.Println("员工信息:")
fmt.Printf("姓名: %s, 年龄: %d, 职位: %s\n", emp.Name, emp.Age, emp.Position)
fmt.Printf("城市: %s, 邮编: %s\n", emp.City, emp.ZipCode)
// 结构体比较
p6 := Person{"测试", 25, "test@example.com", "private"}
p7 := Person{"测试", 25, "test@example.com", "private"}
p8 := Person{"测试", 26, "test@example.com", "private"}
fmt.Println("p6 == p7:", p6 == p7) // true
fmt.Println("p6 == p8:", p6 == p8) // false
// 结构体作为函数参数
printPerson(p6)
updatePerson(&p6)
fmt.Println("更新后的p6:", p6)
// 结构体数组和切片
people := []Person{
{"小明", 20, "xiaoming@example.com", ""},
{"小红", 22, "xiaohong@example.com", ""},
{"小刚", 21, "xiaogang@example.com", ""},
}
fmt.Println("人员列表:")
for i, person := range people {
fmt.Printf("%d. %s (%d岁)\n", i+1, person.Name, person.Age)
}
}
func printPerson(p Person) {
fmt.Printf("姓名: %s, 年龄: %d, 邮箱: %s\n", p.Name, p.Age, p.Email)
}
func updatePerson(p *Person) {
p.Age += 1
fmt.Printf("%s 年龄增加1岁\n", p.Name)
}
3.2 指针(Pointer)
package main
import "fmt"
func main() {
// 基本指针操作
x := 42
p := &x // p指向x
fmt.Printf("x的值: %d\n", x)
fmt.Printf("x的地址: %p\n", &x)
fmt.Printf("p的值(x的地址): %p\n", p)
fmt.Printf("p指向的值: %d\n", *p)
// 通过指针修改值
*p = 100
fmt.Printf("通过指针修改后x的值: %d\n", x)
// 指针的指针
pp := &p
fmt.Printf("pp的值(p的地址): %p\n", pp)
fmt.Printf("pp指向的值(p的值): %p\n", *pp)
fmt.Printf("pp指向的指针指向的值: %d\n", **pp)
// 指针零值
var p1 *int
fmt.Printf("p1的值: %v\n", p1) // <nil>
if p1 == nil {
fmt.Println("p1是nil指针")
}
// 指针和数组
arr := [5]int{1, 2, 3, 4, 5}
p2 := &arr[0]
fmt.Printf("arr[0]的地址: %p\n", &arr[0])
fmt.Printf("p2的值: %p\n", p2)
fmt.Printf("p2指向的值: %d\n", *p2)
// 指针运算(通过unsafe包)
// 注意:unsafe包的使用需要谨慎
/*
import "unsafe"
p3 := &arr[0]
p4 := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(p3)) + unsafe.Sizeof(arr[0])))
fmt.Printf("p4指向的值: %d\n", *p4) // arr[1]的值
*/
// 指针和切片
slice := []int{10, 20, 30, 40, 50}
p5 := &slice[0]
fmt.Printf("slice[0]的地址: %p\n", &slice[0])
fmt.Printf("p5的值: %p\n", p5)
fmt.Printf("p5指向的值: %d\n", *p5)
// 函数指针参数
value := 42
fmt.Printf("调用前: %d\n", value)
increment(&value)
fmt.Printf("调用后: %d\n", value)
// 返回指针的函数
ptr := createInt(100)
fmt.Printf("createInt返回的指针值: %d\n", *ptr)
// 指针和结构体
type Point struct {
X, Y int
}
p6 := &Point{10, 20}
fmt.Printf("Point: (%d, %d)\n", p6.X, p6.Y)
// 使用new创建指针
p7 := new(Point)
p7.X = 30
p7.Y = 40
fmt.Printf("new创建的Point: (%d, %d)\n", p7.X, p7.Y)
}
func increment(p *int) {
*p++
}
func createInt(value int) *int {
return &value // Go编译器会优化,返回局部变量的指针是安全的
}
3.3 接口初识(Interface)
package main
import (
"fmt"
"math"
)
// 定义接口
type Shape interface {
Area() float64
Perimeter() float64
}
// 定义结构体
type Rectangle struct {
Width float64
Height float64
}
type Circle struct {
Radius float64
}
// 实现接口方法
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
// 另一个接口示例
type Writer interface {
Write([]byte) (int, error)
}
type ConsoleWriter struct{}
func (cw ConsoleWriter) Write(data []byte) (int, error) {
n, err := fmt.Print(string(data))
return n, err
}
func main() {
// 接口基本使用
var s Shape
rect := Rectangle{Width: 10, Height: 5}
circle := Circle{Radius: 7}
s = rect
fmt.Printf("矩形: 面积=%.2f, 周长=%.2f\n", s.Area(), s.Perimeter())
s = circle
fmt.Printf("圆形: 面积=%.2f, 周长=%.2f\n", s.Area(), s.Perimeter())
// 接口切片
shapes := []Shape{
Rectangle{Width: 4, Height: 6},
Circle{Radius: 3},
Rectangle{Width: 5, Height: 5},
}
fmt.Println("各种形状:")
for i, shape := range shapes {
fmt.Printf("%d. 面积: %.2f, 周长: %.2f\n",
i+1, shape.Area(), shape.Perimeter())
}
// 空接口(interface{})
var anything interface{}
anything = 42
fmt.Printf("anything = %v (类型: %T)\n", anything, anything)
anything = "Hello"
fmt.Printf("anything = %v (类型: %T)\n", anything, anything)
anything = Rectangle{Width: 10, Height: 20}
fmt.Printf("anything = %v (类型: %T)\n", anything, anything)
// 类型断言
var i interface{} = "hello"
s1, ok := i.(string)
fmt.Printf("i是字符串: %s, ok=%t\n", s1, ok)
f, ok := i.(float64)
fmt.Printf("i是float64: %f, ok=%t\n", f, ok)
// 类型切换
checkType(42)
checkType("hello")
checkType(3.14)
checkType(Rectangle{Width: 10, Height: 20})
// 接口组合
type ReadWriter interface {
Writer
Reader() ([]byte, error)
}
// 使用Writer接口
var w Writer = ConsoleWriter{}
w.Write([]byte("Hello, Interface!\n"))
}
func checkType(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("整数: %d\n", v)
case string:
fmt.Printf("字符串: %s\n", v)
case float64:
fmt.Printf("浮点数: %f\n", v)
case Rectangle:
fmt.Printf("矩形: 宽=%.2f, 高=%.2f\n", v.Width, v.Height)
default:
fmt.Printf("未知类型: %T\n", v)
}
}
4. 类型转换和类型断言
4.1 类型转换
package main
import (
"fmt"
"strconv"
)
func main() {
// 数值类型转换
var i int = 42
var f float64 = float64(i)
var u uint = uint(i)
fmt.Printf("int: %d -> float64: %f -> uint: %d\n", i, f, u)
// 高精度到低精度(可能丢失精度)
var f2 float64 = 3.14159
var i2 int = int(f2)
fmt.Printf("float64: %f -> int: %d\n", f2, i2)
// 字符串和字节切片转换
str := "Hello, 世界!"
bytes := []byte(str)
str2 := string(bytes)
fmt.Printf("字符串: %s\n", str)
fmt.Printf("字节切片: %v\n", bytes)
fmt.Printf("转回字符串: %s\n", str2)
// 字符串和rune切片转换
runes := []rune(str)
str3 := string(runes)
fmt.Printf("rune切片: %v\n", runes)
fmt.Printf("转回字符串: %s\n", str3)
// 字符串和数值转换(使用strconv包)
// 字符串转整数
if i, err := strconv.Atoi("123"); err == nil {
fmt.Printf("字符串转整数: %d\n", i)
}
// 整数转字符串
str4 := strconv.Itoa(456)
fmt.Printf("整数转字符串: %s\n", str4)
// 字符串转浮点数
if f, err := strconv.ParseFloat("3.14159", 64); err == nil {
fmt.Printf("字符串转浮点数: %f\n", f)
}
// 浮点数转字符串
str5 := strconv.FormatFloat(2.71828, 'f', 5, 64)
fmt.Printf("浮点数转字符串: %s\n", str5)
// 布尔值转换
b1, _ := strconv.ParseBool("true")
b2, _ := strconv.ParseBool("0")
str6 := strconv.FormatBool(true)
fmt.Printf("字符串转布尔: %t, %t\n", b1, b2)
fmt.Printf("布尔转字符串: %s\n", str6)
}
4.2 类型断言
package main
import "fmt"
func main() {
// 基本类型断言
var i interface{} = "hello"
// 安全类型断言
if str, ok := i.(string); ok {
fmt.Printf("i是字符串: %s\n", str)
} else {
fmt.Println("i不是字符串")
}
// 不安全的类型断言(可能panic)
str2 := i.(string)
fmt.Printf("直接断言: %s\n", str2)
// 类型切换(更复杂的类型断言)
checkValueType(42)
checkValueType("world")
checkValueType(3.14)
checkValueType([]int{1, 2, 3})
// 接口类型断言
var writer interface{} = &ConsoleWriter{}
if w, ok := writer.(Writer); ok {
w.Write([]byte("通过类型断言调用Write方法\n"))
}
// 检查是否实现多个接口
var rw interface{} = &MyReadWriter{}
if _, ok := rw.(Writer); ok {
fmt.Println("实现了Writer接口")
}
if _, ok := rw.(Reader); ok {
fmt.Println("实现了Reader接口")
}
}
type Writer interface {
Write([]byte) (int, error)
}
type Reader interface {
Read() ([]byte, error)
}
type ConsoleWriter struct{}
func (cw *ConsoleWriter) Write(data []byte) (int, error) {
return fmt.Print(string(data))
}
type MyReadWriter struct{}
func (mrw *MyReadWriter) Write(data []byte) (int, error) {
return len(data), nil
}
func (mrw *MyReadWriter) Read() ([]byte, error) {
return []byte("test data"), nil
}
func checkValueType(v interface{}) {
switch val := v.(type) {
case int:
fmt.Printf("整数类型: %d\n", val)
case string:
fmt.Printf("字符串类型: %s\n", val)
case float64:
fmt.Printf("浮点数类型: %f\n", val)
case []int:
fmt.Printf("整型切片: %v\n", val)
default:
fmt.Printf("未知类型: %T\n", val)
}
}
5. 实践练习
5.1 练习1:学生成绩管理系统
package main
import "fmt"
type Student struct {
Name string
Scores map[string]float64
}
func main() {
// 创建学生
students := []Student{
{
Name: "张三",
Scores: map[string]float64{
"数学": 90,
"英语": 85,
"物理": 88,
},
},
{
Name: "李四",
Scores: map[string]float64{
"数学": 95,
"英语": 92,
"物理": 89,
},
},
}
// 计算平均分
for _, student := range students {
avg := calculateAverage(student.Scores)
fmt.Printf("%s 的平均分: %.2f\n", student.Name, avg)
}
// 找出每门课的最高分
subjectMax := findSubjectMax(students)
fmt.Println("每门课的最高分:")
for subject, maxScore := range subjectMax {
fmt.Printf("%s: %.2f\n", subject, maxScore)
}
}
func calculateAverage(scores map[string]float64) float64 {
var sum float64
for _, score := range scores {
sum += score
}
return sum / float64(len(scores))
}
func findSubjectMax(students []Student) map[string]float64 {
result := make(map[string]float64)
for _, student := range students {
for subject, score := range student.Scores {
if currentMax, exists := result[subject]; !exists || score > currentMax {
result[subject] = score
}
}
}
return result
}
5.2 练习2:简单图书管理系统
package main
import "fmt"
type Book struct {
ISBN string
Title string
Author string
Price float64
Count int
}
type Library struct {
books map[string]Book // ISBN -> Book
}
func NewLibrary() *Library {
return &Library{
books: make(map[string]Book),
}
}
func (l *Library) AddBook(book Book) {
l.books[book.ISBN] = book
fmt.Printf("添加图书: %s\n", book.Title)
}
func (l *Library) RemoveBook(isbn string) {
if book, exists := l.books[isbn]; exists {
delete(l.books, isbn)
fmt.Printf("删除图书: %s\n", book.Title)
} else {
fmt.Printf("图书不存在: %s\n", isbn)
}
}
func (l *Library) SearchByISBN(isbn string) (*Book, bool) {
book, exists := l.books[isbn]
return &book, exists
}
func (l *Library) SearchByAuthor(author string) []Book {
var result []Book
for _, book := range l.books {
if book.Author == author {
result = append(result, book)
}
}
return result
}
func (l *Library) UpdatePrice(isbn string, newPrice float64) bool {
if book, exists := l.books[isbn]; exists {
book.Price = newPrice
l.books[isbn] = book
return true
}
return false
}
func main() {
library := NewLibrary()
// 添加图书
library.AddBook(Book{
ISBN: "978-7-111-12345-6",
Title: "Go语言实战",
Author: "张三",
Price: 89.00,
Count: 10,
})
library.AddBook(Book{
ISBN: "978-7-111-12346-3",
Title: "Go并发编程",
Author: "李四",
Price: 99.00,
Count: 5,
})
library.AddBook(Book{
ISBN: "978-7-111-12347-0",
Title: "Go Web开发",
Author: "张三",
Price: 79.00,
Count: 8,
})
// 查询图书
if book, found := library.SearchByISBN("978-7-111-12345-6"); found {
fmt.Printf("找到图书: %+v\n", *book)
}
// 按作者查询
books := library.SearchByAuthor("张三")
fmt.Println("张三的图书:")
for _, book := range books {
fmt.Printf("- %s: %.2f元\n", book.Title, book.Price)
}
// 更新价格
if library.UpdatePrice("978-7-111-12345-6", 95.00) {
fmt.Println("价格更新成功")
}
// 删除图书
library.RemoveBook("978-7-111-12346-3")
}
总结
本章详细介绍了Go语言的数据类型,包括:
- 基本数据类型:布尔型、整型、浮点型、复数类型、字符串
- 复合数据类型:数组、切片、映射
- 自定义类型:结构体、指针、接口
- 类型转换和断言:数值转换、字符串转换、类型断言
掌握这些数据类型是Go编程的基础,在后续的学习中会频繁使用到这些知识。特别是切片和映射,它们是Go语言中最常用的数据结构,需要重点掌握。
3554



被折叠的 条评论
为什么被折叠?



