Golang-02基础编程_基本数据类型与复合数据类型

【Golang学习之旅】Go 语言数据类型详解(string、slice、map等) ✅ 适合人群:Golang 新手 | 后端开发者 | 面试求职者✅ 文章亮点:超详细解析 + 代码示例 + 实战应用✅ 目标:掌握 Go 语言核心数据类型,助你写出高效、稳定的 Go 代码!📌 本篇文章介绍了 Go 语言的常见数据类型,包括 string、slice、map 等,帮助你掌握 Go 语言基础。📌 进阶学习:Go 并发(Goroutine)、微服务(gRPC)、Web 开发(Gin 框架)Go 官方文档。 阅读详情

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语言中最常用的数据结构,需要重点掌握。

Go语言的数据类型 在Go语言中,可以基于已有的类型定义新类型,这被称为用户自定义类型。自定义类型可以使代码更具可读性和可维护性。用户可以基于基本类型定义新的类型,如下例所示:```gofmt.Println("温度转换:", tempF)```用户还可以基于结构体进一步扩展,设计更复杂的数据模型。例如,定义一个表示车辆的结构体。```goYear intfmt.Println("我的车:", myCar)```Go语言丰富而强大的数据类型系统为开发者提供了多种选择,适用于不同的数据处理需求。 阅读详情

相关推荐

关于RT-Thread中PWM无法正常输出的学习

按照官方的PWM配置,并没有输出PWM,网上有比较多的办法,试了很多,有些还是不能实现输出,这里做个记录。记录自己完成PWM输出的过程,以及修改的地方。 关于STM32CubeMX配置就不多说了,网上有很多。 首先必定是按照流程来,一定一定按照流程来!!! 需要注意的是加上通道数!!!! 这是流程上没有的,也是RTT的一点小BUG吧 配上board.c中添加的代码,我用的是PA2定时2的通道3,需要使用的朋友修改对应定时器和GPIO! void HAL_TIM_Base_MspInit(TIM_Han

weixin_42566346的博客 3554

【Go语言】语法基础之变量、数据类型详解

Go语言,又称Golang,是由Google公司开发的一种现代编程语言。它起源于2007年,并在2009年正式对外发布。Go语言旨在提高软件开发的效率、可靠性和可维护性,特别在处理并发性方面表现出色。2、Go语言特点Go语言内置并发性支持,允许开发者构建高度并发和可扩展的应用。它提供了goroutine(轻量级线程)和channel(通信管道)等功能,简化了并发编程。Go语言拥有高效的垃圾回收机制,自动释放不再使用的内存。这减轻了开发者管理内存的负担,提高了程序的稳定性和可靠性。

博客虽小,世界尽在其中 3640

【Unity3D】RTS Engine 笔记一

RTS Engine 中配置一个新场景, 初步认识GameManager、设置地形以及配置地形网格搜索

ViYeye的博客 1649

golang 数据类型【复合数据类型】

golang 数据类型【复合数据类型】

Lai助网络科技的博客 1521

红外协议 IR NEC 协议深度解析-简单易懂协议详解

1. 协议特征 使用双向编码(又称曼彻斯特编码); 使用38K载波对编码后的波形进行调制; 位时间 1.12ms 或 2.25ms 2. 调制 定义脉冲560µS为脉冲基本宽度T; 根据脉冲时间长短来解码。推荐载波占空比为1/3至1/4: (1) Logic “1” 位宽为2.25ms,脉冲时间560us(T + 3T); (2) Logic “0” 位宽为1.12ms,脉冲时间560us(T + T)。 (3 ) 重复码: 位宽为11.25ms,脉冲时间9ms(16T + 4T)。 3. 协议

代码打工人的博客 1万+

物料主数据管理难在哪?基于AI算法的数据清洗工具了解一下

企企通打造的一套以AI模型和算法为核心的产品及服务,可针对各类企业的不同主数据痛点难点,提供多种解决方案,能够快速完成物料主数据清洗、识别、匹配、梳理,满足一物一码、分类梳理、一品多商、多维度比价、精准寻源选品、建立标准物料库、供应商及客户主数据清洗等业务场景需求。随着AI技术的快速发展,智能算法在数据清洗领域的应用越来越广泛,越来越多的数据清洗工作已经开始交由智能算法完成,通过自动化的方式处理大量数据,识别和纠正错误,填补缺失值,检测异常值,以及执行其他数据预处理任务,并提高效率并减少人为错误。

QQT_qqt的博客 1364

编程笔记 Golang基础 014 数据类型概述

Go 语言的数据类型系统涵盖了基本数据类型、复合数据类型以及引用类型。

明月看潮生的博客 1253

用 Python 和 uiautomation 实现微信批量发送

思路是这样,将要发送的人员名单(包括称呼)以及发送内容都维护到Excel里,程序运行时读取Excel里内容,自动搜索人员姓名(微信昵称或备注名),填入要发送的内容,拼接上称呼(如果需要的话)自动点击发送,这样轮巡直至名单人员全部发送完成。、

jankingdom的专栏 1471

Golang_02: Go语言 数据类型:基础类型 与 复合类型

Go 的数据类型可分为 基础类型、复合类型、引用类型、接口类型 等。其中 基础类型、复合类型 是常用的 数据结构 类型,可细分为:Go 使用 关键字声明 变量,格式:其中 类型 和 表达式赋值 可以省略一个,但不能都省略(需要能够推导出变量的类型)。如果省略初始化赋值表达式,则变量的初始值为对应类型的 零值(默认值),Go 不存在未初始的变量。各类型的 零值:示例:可以用 声明多少变量:可同时声明多个不同类型的变量。短变量声明,在函数中,可以使用 短变量声明 来声明和初始化局部变量。

谢TS的博客 798

Dify DSL文件分享 Dify讨论群 大模型token资源等(持续收集更新)

基于LLMOps平台-Dify的一站式学习平台。包含不限于:Dify案例、DSL文件分享、模型接入、Dify交流讨论等各类资源分享。

同名公众号:dify实验室 3714

CAN总线入门(硬件部分)

这篇博客讲述CAN总线入门知识。

记得诚 1万+

青少年编程与数学 02_001 GO语言程序设计基础 03课题、数据类型

Go语言的数据类型系统包括基本数据类型、复合数据类型和引用类型。基本数据类型包括布尔型、整数型、浮点型、复数型和字符串。复合数据类型包括数组、切片、结构体、接口。引用类型包括指针、函数类型、通道、映射和错误类型。特殊类型有空接口。布尔型用于逻辑判断,数字类型用于数值表示,字符串用于文本数据表示。每种类型都有其特定的使用场景和内存占用。

明月看潮生的博客 1513

【Bug已解决】Codex 切换 model_provider 后历史会话消失的解决方案

方案适用场景推荐指数切回原 provider 验证排查的第一步,确认数据是否真的丢失⭐⭐⭐⭐⭐查看本地会话文件进一步确认数据完整性⭐⭐⭐⭐⭐查阅跨 provider 恢复命令官方是否提供了对应功能⭐⭐⭐使用社区辅助工具需要频繁切换 provider 的场景⭐⭐⭐定期备份配置目录任何场景下的通用保险措施⭐⭐⭐⭐切换后历史会话"消失"的本质是客户端的会话列表展示逻辑受当前活跃 provider 状态过滤,而不是原始数据文件被真正删除。

一键难忘的博客 5999

Go语言复合数据类型

Go语言是一种现代化且高效的编程语言,其支持多种数据类型,包括基本数据类型和复合数据类型。在前面的文章中,我们已经介绍了Go语言的基本数据类型,包括整数、浮点数、布尔值和字符串等。本文将重点介绍Go语言的复合数据类型,包括数组、切片、映射和结构体等。这些数据类型是Go语言中最常用的数据类型之一,可以用于存储和处理复杂的数据结构,是每个Go语言程序员必须掌握的知识点。本文将着重介绍这些数据类型的定义、初始化和使用方法,希望能够帮助读者更好地理解Go语言中的复合数据类型。

Kali与编程 972

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

青少年编程与数学 02-008 Pyhon语言编程基础 05课题、数据类型

本文介绍了Python数据类型及其与Go和JavaScript数据类型的比较。Python是动态类型语言,支持多种数据类型,包括数字、序列、集合、映射、布尔、二进制数据和None类型。文章比较了Python与Go在类型系统、基本数据类型、复合数据类型、可变性、类型转换和接口以及空值和错误处理方面的差异,以及Python与JavaScript在类型系统、基本数据类型、复合数据类型、可变性、特殊值、类型转换、错误处理、函数和对象方面的差异。

明月看潮生的博客 2088

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Golang基础 - 复合数据类型

Go的复合数据类型提供了多种构建复杂数据结构的方法。数组和切片适合用于处理集合数据,映射则用于存储键值对,结构体用于将不同类型的数据组织在一起,而接口则提供了灵活的多态能力。这些复合数据类型是Go语言强大且灵活的基础。

weixin_43825008的博客 765

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Golang入门简介与基本语法学习

Golang的出现背景Go语言,或我们通常称之为Golang,它的设计哲学深受其创造者的软件开发经验影响,它旨在实现快速编译、高性能、静态类型检查以及简洁明了的代码风格。是由Google开发的一个开源编程语言,它首次公布于2009年11月,由Robert Griesemer, Rob Pike, 和 Ken Thompson联合设计。这三位在计算机科学领域有着不俗的成就,Ken Thompson特别以其对UNIX操作系统和C语言的贡献闻名。

码农小郑有话说的博客 4522

100天精通Golang(基础入门篇)——第5天: Go语言中的数据类型学习

本篇文章介绍了Go语言中常用的数据类型,包括整数类型、浮点数类型、布尔类型和字符串类型。每种数据类型的概念和用法都进行了详细的说明,并给出了与Java和Python的对比代码案例。通过学习这些数据类型,读者可以掌握Go语言中数据的存储和操作方式,为编写高效、可靠的Go程序打下坚实的基础。

猫头虎技术团队:授渔优于赠鱼,兴趣引领智慧,探索之乐尤显珍贵。商务合作+:Libin9iOak ,万粉变现+:优快云WF,猫头虎承诺每年免费为100名C站创作者做账号流量诊断服务!全网搜:猫头虎技术团队,点击文章底部名片或直接私信我一切皆可谈,快找虎哥! 5万+

golang基础看这个就够了

本文可以快速了解go基础和上手,适合小白使用,更适合有一定语言基础想快速学习go语言的(因为我就是java转go的哈哈)

代码写得顺,火锅吃得香!🔥✨ 1071

Golang 基本数据类型

在Go语言中数据类型分为基本数据类型和复合数据类型。整型、浮点型、布尔型、字符串。数组、切片、结构体、函数、map、通道( channel )、接口等。本文分享了Golang基本数据类型的学习心得,作为入门阶段的知识点总结。由于篇幅限制,后续会继续深入探讨更复杂的语法特性。学习编程语言需要循序渐进,建议新手从基础数据类型开始练习,逐步掌握核心概念。欢迎在评论区交流学习经验或提出疑问。

whhhhhhhhhw的博客 1266

GoLang教程003:数据类型介绍

在 Go 语言中,数据类型是构建程序的基础,分为以下几类:基本类型、复合类型/派生类型。

WwLK123的博客 1208

Golang复合类型

前言 上文 Golang 基本类型 中我们介绍了golang 基本类型的常见用法,本文将介绍 golang 中的复合数据类型,常用的复合数据类型有 array 数组,slice 切片,map 字典 和 struct 四种。 数组 数组是一个由固定长度的特定类型元素组成的序列,由于长度固定,在实际业务场景下使用较为不便,因此在 go 中很少直接使用。 数组的长度是数组类型的一个组成部分,因此 [3]int 和 [4]int 是两种不同的数组类型。数组的长度必须是常量表达式,因为数组的长度需要在编译阶段确定。

wallace_www的博客 1万+

【Go开发】Go语言基本语法入门:数据类型与方法定义

在Go语言中,方法是一种特殊的函数,它属于一个类型。// 方法体// 声明这是一个可执行程序// 导入fmt包用于格式化输出/*** Person结构体定义**/Age int/*** 定义一个方法**/// 程序启动方法// 创建一个新的Person实例本文介绍了Go语言的基本语法,包括数据类型、变量声明和方法定义。掌握这些基础知识,可以帮助你更好地学习Go语言,为后续深入学习打下坚实基础。在实际开发过程中,不断实践和积累经验,才能熟练运用Go语言解决问题。

一个不断前行的程序者 1469

GO语言中复合数据类型的声明与使用

复合数据类型   golang中有七种复合数据类型,包括指针、数组、slice、map、chan、struct与interface。本文将简单介绍这几种类型的声明与使用   文中使用到的格式化输出占位符的用法可见Go语言中文文档的fmt包,比如 指针   go语言的指针操作包括&与*,赋值语句中*T在=左边表示指针声明,*T在=右边表示取指针指向的值   指针相当于存放变量所在的地址,比如声明了一个变量a := 10,其地址为0xc00000a0a0,那么p := &a的p值即为0xc00

Jcduhdt的博客 619

Go 基本数据类型

Go 基本数据类型

wgchen 1009

GO 复合数据类型

一、数组 1、声明 2、访问、修改 3、作为参数传递 二、切片 1、创建 2、增 3、删 4、改 5、查 三、映射 1、创建 2、增 3、删 4、改 5、查

风中的劲草 565
上一篇: Golang-01基础编程_开发环境准备
下一篇: Golang-03基础编程_控制流与函数
d3y1
博客等级 码龄12年 1438粉丝 2773原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值