【Go语言学习系列09】Go基础语法(七):指针

【Go语言】深入解读Go语言中的指针,助你拨开迷雾见月明 在Go语言中,指针是一种特殊的变量类型,它用于存储变量的内存地址。通过指针,程序可以直接访问和修改变量的值,这在处理大型数据结构、优化内存使用和提高程序性能时非常有用。本文将结合具体案例,详细讲解Go语言中指针的用法,包括定义指针、使用指针访问和修改变量值、指针作为函数参数和返回值、指针数组和切片、结构体指针、空指针检查等。 阅读详情

📚 原创系列: “Go语言学习系列”

🔄 转载说明: 本文最初发布于"Gopher部落"微信公众号,经原作者授权转载。

🔗 关注原创: 欢迎扫描文末二维码,关注"Gopher部落"微信公众号获取第一手Go技术文章。

📑 Go语言学习系列导航

本文是【Go语言学习系列】的第9篇,当前位于第一阶段(入门篇)

🚀 第一阶段:入门篇
  1. Go语言简介与环境搭建
  2. Go开发工具链介绍
  3. Go基础语法(一):变量与数据类型
  4. Go基础语法(二):流程控制
  5. Go基础语法(三):函数
  6. Go基础语法(四):数组与切片
  7. Go基础语法(五):映射
  8. Go基础语法(六):结构体
  9. Go基础语法(七):指针 👈 当前位置
  10. Go基础语法(八):接口
  11. 错误处理与异常
  12. 第一阶段项目实战:命令行工具

📚 查看完整Go语言学习系列导航

📖 文章导读

在本文中,您将学习:

  • 指针的基本概念与内存模型
  • Go指针的安全特性与C/C++指针的区别
  • 指针的声明、初始化与操作方法
  • 函数参数中值传递与指针传递的应用场景
  • 结构体与指针的结合使用技巧
  • 常见的指针陷阱与解决方案
  • unsafe包的高级应用与注意事项

指针是Go语言中非常重要的特性,它既提供了直接操作内存的能力,又通过严格的安全限制避免了常见的内存问题。本文将帮助您全面掌握指针的使用,提升代码性能,同时避免常见陷阱。

Go指针示意图


Go基础语法(七):指针详解与最佳实践

指针是Go语言继承自C语言的重要特性,用于存储变量的内存地址。与C/C++不同,Go指针设计更加简洁和安全,既提供了直接操作内存的能力,又通过去除指针算术等危险操作防止了内存错误。本文将深入讲解Go语言指针的原理、应用和最佳实践。

一、指针基础

1.1 什么是指针

指针是一种特殊的变量,它不直接存储实际数据,而是存储另一个变量在内存中的地址。通过指针,我们可以:

  • 直接访问和修改内存中的数据
  • 避免大型数据的复制开销
  • 实现引用传递(间接方式)
  • 构建复杂的数据结构(如链表、树等)

在Go中,指针类型的声明使用*符号:

var p *int // 声明一个指向int类型的指针

1.2 指针的基本操作

Go指针有三个基本操作:获取地址、解引用和初始化。

1. 获取地址:使用&操作符获取变量的内存地址。

x := 10
p := &x // p存储了x的内存地址
fmt.Printf("x的值: %d\n", x)          // 10
fmt.Printf("x的内存地址: %p\n", &x)     // 0xc000018030 (地址值会不同)
fmt.Printf("p存储的地址: %p\n", p)      // 0xc000018030 (与上面相同)

2. 解引用:使用*操作符访问指针指向的值。

*p = 20 // 通过指针修改x的值
fmt.Printf("修改后的x值: %d\n", x)      // 20
fmt.Printf("通过指针读取x: %d\n", *p)   // 20

3. 指针初始化:指针的零值是nil,表示不指向任何地址。

var p1 *int // 零值为nil
fmt.Println(p1)         // <nil>
fmt.Println(p1 == nil)  // true

// 初始化指针的几种方式
// 方式1:指向已有变量
x := 10
p2 := &x

// 方式2:使用new函数
p3 := new(int) // 分配内存并返回指针
*p3 = 100      // 设置值

1.3 Go指针的安全性

Go指针较C/C++更加安全,主要体现在以下限制:

  1. 没有指针算术:不能对指针进行加减运算。

    x := [5]int{1, 2, 3, 4, 5}
    p := &x[0]
    // p++ // 编译错误:无效的操作
    
  2. 禁止指针类型转换:不能随意将一种类型的指针转换为另一种类型(除非使用unsafe包)。

    f := 3.14
    // ip := (*int)(&f) // 编译错误:非法类型转换
    
  3. 自动垃圾回收:不需要手动释放内存,避免了悬空指针和内存泄漏问题。

  4. 防止空指针解引用:对nil指针的解引用会导致运行时panic,而不是未定义行为。

    var p *int
    // fmt.Println(*p) // 运行时错误:panic: runtime error: invalid memory address or nil pointer dereference
    

二、指针的应用

2.1 指针作为函数参数

在Go中,函数参数默认是值传递(复制)。使用指针作为参数可以实现引用传递的效果:

// 值传递:无法修改原始值
func increment(val int) {
    val++
    fmt.Println("函数内:", val) // val被修改
}

// 指针传递:可以修改原始值
func incrementPointer(val *int) {
    *val++
    fmt.Println("函数内:", *val) // 原始值被修改
}

func main() {
    x := 10
    
    increment(x)
    fmt.Println("值传递后:", x) // x不变,仍为10
    
    incrementPointer(&x)
    fmt.Println("指针传递后:", x) // x变为11
}

何时使用指针作为函数参数?

  1. 需要在函数内修改传入变量的值时
  2. 传递大型结构体以避免复制开销时
  3. 传递切片、映射等引用类型时通常不需要使用指针(因为它们本身已经包含了指针)

2.2 结构体与指针

结构体与指针的结合使用非常常见:

type Person struct {
    Name string
    Age  int
}

// 创建并返回结构体指针
func NewPerson(name string, age int) *Person {
    return &Person{
        Name: name,
        Age:  age,
    }
}

// 使用指针接收者的方法
func (p *Person) Birthday() {
    p.Age++
}

// 使用值接收者的方法
func (p Person) Info() string {
    return fmt.Sprintf("%s, %d岁", p.Name, p.Age)
}

func main() {
    // 直接创建结构体指针
    p1 := &Person{"张三", 30}
    
    // 使用工厂函数创建
    p2 := NewPerson("李四", 25)
    
    // Go自动解引用 - 这两种写法等价
    fmt.Println((*p1).Name) // 张三
    fmt.Println(p1.Name)    // 张三 (简便写法)
    
    // 调用方法
    p2.Birthday()
    fmt.Println(p2.Age) // 26
}

重要的是:在处理大结构体时,方法接收者应该使用指针类型,以避免每次调用方法时复制整个结构体。

2.3 指针与切片

切片已经包含了指向底层数组的指针,因此通常不需要使用指针传递切片:

// 修改切片元素 - 不需要指针
func modifySlice(s []int) {
    if len(s) > 0 {
        s[0] = 100 // 修改会影响原切片
    }
}

// 但修改切片本身(如长度)不会反映到原切片
func appendToSlice(s []int) {
    s = append(s, 200) // 这个修改不会影响原切片
}

// 使用指针可以使得修改切片本身的操作反映到原切片
func appendToSlicePtr(s *[]int) {
    *s = append(*s, 200) // 这会影响原切片
}

func main() {
    nums := []int{1, 2, 3}
    
    modifySlice(nums)
    fmt.Println(nums) // [100 2 3]
    
    appendToSlice(nums)
    fmt.Println(nums) // [100 2 3] (未改变)
    
    appendToSlicePtr(&nums)
    fmt.Println(nums) // [100 2 3 200] (已改变)
}

2.4 指针数组与数组指针

指针数组和数组指针是两个容易混淆的概念:

// 指针数组:元素为指针的数组
func pointerArray() {
    x, y, z := 1, 2, 3
    pointers := [3]*int{&x, &y, &z}
    
    fmt.Println(*pointers[0]) // 1
    *pointers[1] = 20
    fmt.Println(y)           // 20 (已被修改)
}

// 数组指针:指向数组的指针
func arrayPointer() {
    arr := [3]int{1, 2, 3}
    p := &arr
    
    fmt.Println(p[0]) // 1 (Go允许通过指针直接索引)
    p[1] = 20
    fmt.Println(arr)  // [1 20 3] (已被修改)
}

三、指针和内存管理

3.1 new 与 make 的区别

new和make都用于分配内存,但用途不同:

// new: 为任何类型分配零值内存,并返回指针
p1 := new(int)     // *int 指向 0
p2 := new([5]int)  // *[5]int 指向 [0,0,0,0,0]
p3 := new(struct{name string}) // 指向空结构体

// make: 仅用于创建切片、映射和通道,返回初始化的实例
s1 := make([]int, 5)    // []int 长度为5的切片
m1 := make(map[string]int) // map 空映射
c1 := make(chan int, 10)  // chan 带缓冲的通道

主要区别:

  • new(T) 返回 *T,指向零值
  • make(T, ...) 返回初始化的 T(不是指针)
  • 只有切片、映射和通道可以使用 make

3.2 垃圾回收与指针

Go具有自动垃圾回收机制,使用三色标记算法回收不再使用的内存:

func createBigArray() *[1000000]int {
    // 即使函数返回,大数组也不会立即被回收
    arr := [1000000]int{}
    return &arr
}

func main() {
    // 不需要担心内存泄漏
    p := createBigArray()
    // 使用p...
    
    // 当p不再使用时,垃圾回收器会自动回收数组内存
    p = nil // 显式地放弃引用(可选)
}

虽然有垃圾回收,但良好的实践仍是尽早释放大型对象的引用:

func processLargeData(data []byte) {
    // 处理数据...
    
    // 处理完毕后,如果不再需要数据
    // 显式置nil可以帮助垃圾回收器更快回收
    data = nil
}

3.3 指针与并发安全

在并发环境中使用指针需要特别小心:

// 不安全:多个goroutine同时访问
func unsafeConcurrent() {
    counter := 0
    
    for i := 0; i < 1000; i++ {
        go func() {
            c := &counter
            *c++ // 竞态条件
        }()
    }
}

// 安全:使用互斥锁
func safeConcurrent() {
    counter := 0
    var mu sync.Mutex
    
    for i := 0; i < 1000; i++ {
        go func() {
            mu.Lock()
            counter++
            mu.Unlock()
        }()
    }
}

// 更安全:使用通道或atomic包
func atomicConcurrent() {
    var counter int32 = 0
    
    for i := 0; i < 1000; i++ {
        go func() {
            atomic.AddInt32(&counter, 1)
        }()
    }
}

四、unsafe包与高级指针操作

4.1 unsafe包简介

unsafe包允许执行底层的指针操作,但使用时需谨慎:

import (
    "fmt"
    "unsafe"
)

func unsafePointer() {
    // 创建一个float64值
    f := 3.14159
    
    // 1. 将*float64转换为unsafe.Pointer
    ptr := unsafe.Pointer(&f)
    
    // 2. 将unsafe.Pointer转换为*uint64
    bits := (*uint64)(ptr)
    
    // 查看float64的内部位表示
    fmt.Printf("%f的位表示: %b\n", f, *bits)
}

4.2 指针类型转换

使用unsafe.Pointer可以实现不同类型指针之间的转换:

func typeConversion() {
    // int16数组
    nums := []int16{1, 2, 3, 4, 5}
    
    // 转换为[]int32(错误示例 - 仅用于演示)
    // 获取切片头部信息的指针
    sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&nums))
    
    // 修改元素大小(警告:这是不安全的!)
    sliceHeader.Len /= 2
    sliceHeader.Cap /= 2
    
    // 创建一个新的int32切片指向相同的数据
    int32Slice := *(*[]int32)(unsafe.Pointer(sliceHeader))
    
    // 这可能导致内存损坏!
    fmt.Println(int32Slice)
}

警告:上述代码仅用于演示,实际使用时应极度谨慎。这种技术可能导致内存损坏、不可预测的行为和安全问题。

4.3 内存布局与对齐

使用unsafe包可以检查内存对齐和布局:

type Example struct {
    A byte
    B int64
    C byte
}

func memoryLayout() {
    e := Example{}
    
    fmt.Printf("结构体大小: %d字节\n", unsafe.Sizeof(e))
    
    // 字段偏移量
    fmt.Printf("字段A偏移量: %d\n", unsafe.Offsetof(e.A))
    fmt.Printf("字段B偏移量: %d\n", unsafe.Offsetof(e.B))
    fmt.Printf("字段C偏移量: %d\n", unsafe.Offsetof(e.C))
    
    // 字段对齐要求
    fmt.Printf("字段A对齐要求: %d\n", unsafe.Alignof(e.A))
    fmt.Printf("字段B对齐要求: %d\n", unsafe.Alignof(e.B))
    fmt.Printf("字段C对齐要求: %d\n", unsafe.Alignof(e.C))
}

4.4 零开销类型转换

unsafe包可以实现零开销的类型转换,特别是在处理底层字节操作时:

func zeroOverheadConversion() {
    // 创建一个字符串
    s := "Hello, unsafe world!"
    
    // 直接获取字符串的底层字节,无需复制
    bytes := *(*[]byte)(unsafe.Pointer(
        &reflect.SliceHeader{
            Data: (*reflect.StringHeader)(unsafe.Pointer(&s)).Data,
            Len:  len(s),
            Cap:  len(s),
        },
    ))
    
    fmt.Println(bytes) // 输出字节切片
    
    // 警告:修改这些字节会导致不可预测的行为!
    // bytes[0] = 'h' // 非常危险!
}

替代安全方法:如果可能,始终使用标准库提供的安全方法:

// 安全方法:有复制开销但是安全
s := "Hello, world!"
bytes := []byte(s)

五、实践应用

5.1 自定义链表实现

使用指针实现简单的单向链表:

type Node struct {
    Value int
    Next  *Node
}

type LinkedList struct {
    Head *Node
    Tail *Node
    Size int
}

// 添加元素到链表尾部
func (list *LinkedList) Append(value int) {
    newNode := &Node{Value: value}
    
    if list.Head == nil {
        list.Head = newNode
        list.Tail = newNode
    } else {
        list.Tail.Next = newNode
        list.Tail = newNode
    }
    
    list.Size++
}

// 打印链表
func (list *LinkedList) Print() {
    current := list.Head
    for current != nil {
        fmt.Printf("%d -> ", current.Value)
        current = current.Next
    }
    fmt.Println("nil")
}

func main() {
    list := LinkedList{}
    list.Append(10)
    list.Append(20)
    list.Append(30)
    
    list.Print() // 输出: 10 -> 20 -> 30 -> nil
}

5.2 高效字符串处理

使用指针可以实现高效的字符串处理:

// 计算字符串中字符的频率
func characterFrequency(text string) map[rune]int {
    freq := make(map[rune]int)
    
    // 直接使用range遍历字符串中的Unicode字符
    for _, char := range text {
        freq[char]++
    }
    
    return freq
}

// 高效检查字符串是否回文(双指针技术)
func isPalindrome(s string) bool {
    // 转换为小写并过滤非字母数字字符
    var filtered []rune
    for _, r := range s {
        if unicode.IsLetter(r) || unicode.IsDigit(r) {
            filtered = append(filtered, unicode.ToLower(r))
        }
    }
    
    // 使用双指针判断是否回文
    for i, j := 0, len(filtered)-1; i < j; i, j = i+1, j-1 {
        if filtered[i] != filtered[j] {
            return false
        }
    }
    
    return true
}

5.3 内存池与对象复用

使用指针实现简单的对象池,减少垃圾回收压力:

type Buffer struct {
    data [4096]byte
}

type BufferPool struct {
    pool sync.Pool
}

func NewBufferPool() *BufferPool {
    return &BufferPool{
        pool: sync.Pool{
            New: func() interface{} {
                return &Buffer{}
            },
        },
    }
}

func (p *BufferPool) Get() *Buffer {
    return p.pool.Get().(*Buffer)
}

func (p *BufferPool) Put(b *Buffer) {
    p.pool.Put(b)
}

func main() {
    pool := NewBufferPool()
    
    // 获取缓冲区
    buffer := pool.Get()
    
    // 使用缓冲区
    // ...
    
    // 使用完毕后归还
    pool.Put(buffer)
}

👨‍💻 关于作者与Gopher部落

"Gopher部落"专注于Go语言技术分享,致力于为开发者提供从入门到精通的完整学习路线。我们提供:

  • 📚 系统化的Go语言学习教程
  • 🔥 最新Go生态技术动态
  • 💡 实用开发技巧与最佳实践
  • 🚀 大厂项目实战经验分享

🎁 读者福利

关注"Gopher部落"微信公众号,即可获得:

  1. 完整Go学习路线图:从入门到高级的完整学习路径
  2. 面试题集锦:精选Go语言面试题及答案解析
  3. 项目源码:实战项目完整源码及详细注释
  4. 个性化学习计划:根据你的水平定制专属学习方案

如果您觉得这篇文章有帮助,请点赞、收藏并关注,这是对我们最大的支持!

Go 学习笔记(13)— 指针定义、指针特点、空指针、指针数组、指向指针的指针、指针作为函数入参 1. 指针定义 Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。 获取变量在内存中地址: package main import "fmt" func main() { var a int = 10 fmt.Printf("变量的地址: %x\n", &a ) } 输出结果: 变量的地址: 20818a220 一个指针变量指向了... 阅读详情

相关推荐

Go语言学习之cgo(golang与C语言相互调用)

生命不止,继续 go go go !!!几乎所有的编程语言都有C语言的影子,当然golang也不例外。可以看到golang的创始者们与c language有着密切的联系。所有,golang和c语言的相互调用也是理所应当。什么场合会使用Go与C的互操作呢? 下面的地址给出这样的答案:http://tonybai.com/2012/09/26/interoperability-between-go-a

一蓑烟雨任平生 也无风雨也无晴 2万+

Go语言指针 【Go语言圣经笔记】

摘自:Go语言圣经(简体中文版) 2.3.2 指针 一个变量对应一个保存了变量对应类型值的内存空间。 普通变量在声明语句创建时被绑定到一个变量名,比如叫x的变量,但是还有很多变量始终以表达式方式引入,例如x[i]或者x.f变量。所有这些表达式一般都是读取一个变量的值,除非它们是出现在赋值语句的左边,这种时候是给对应变量赋予一个新的值。 一个指针的值是另一个变量的地址。一个指针对应变量在内存中的存储位置。并不是每一个值都会有一个内存地址,但是对于每一个变量必然有对应的内存地址。通过指针,我们可以直接读或更.

Steve Wang's blog 360

【NTN 卫星通信】使用地面网络和卫星网络接入的终端应用场景

卫星接入有广覆盖的特点, 可以改善地面接入网覆盖或无线条件差的地区(例如多径干扰)的服务可用性。对于高速移动中需要实时业务的终端,如IMS语音/视频会议,可以通过地面接入和卫星接入同时实现与5G系统的双连接,在地面接入网不可用的情况下获得连续可靠的业务。

weixin_43603524的博客 2558

【go语言】函数与指针

go函数与指针

qq_53893431的博客 865

树莓派CM4 PCIe扩展方案与ASM1184e芯片应用

PCIe(Peripheral Component Interconnect Express)是计算机硬件中重要的高速串行总线标准,广泛应用于存储、网络等设备连接。其核心原理是通过差分信号实现高带宽传输,PCIe Gen2 x1的理论带宽可达5Gbps。在嵌入式开发中,PCIe扩展技术能有效解决单板计算机接口不足的问题,特别适合树莓派等微型平台。ASMedia ASM1184e作为PCIe交换芯片,可将单个接口扩展为多个,支持热插拔且免驱动,极大提升了工程灵活性。通过PCIe交换机方案,开发者能在树莓派CM

weixin_42602368的博客 421

ArcGIS遥感影像分类技术在植被覆盖度计算中的应用

本文详细介绍了如何利用ArcGIS遥感影像分类技术高效计算植被覆盖度。通过数据准备、监督与非监督分类方法详解,并结合制表分析与栅格计算器进行面积统计,最终实现从分类图到覆盖度百分比的全流程自动化与可视化,为生态评估与规划提供精准数据支持。

weixin_29091445的博客 420

go语言指针

go语言指针

岳来的博客 1632

【Ubuntu2404】Ubuntu24.04安装NVIDIA驱动/CUDA/cuDNN搭建神经网络训练环境

NVIDIA 驱动、CUDA和cuDNN是紧密相关但各自具有独特功能的技术,它们共同为图形处理单元(GPU)加速的应用程序提供了强大的支持。本文主要介绍如何安装 `NVIDIA` 驱动、CUDA及cuDNN,为后续神经网络训练提供支持。本文主要介绍Ubuntu24.04安装NVIDIA驱动、CUDA和cuDNN的流程。

王阿巴和王咕噜 1万+

【Go语言学习系列00】Go语言学习系列导航

本文是Go语言学习系列的导航文档,提供了从入门到精通的学习路径,包含各阶段文章链接和内容概述,帮助读者系统化学习Go语言。

GopherTribe的博客 1575

Palantir的Ontology:从静态知识图谱到动态业务引擎的跃迁

本文探讨了Palantir的Ontology技术如何将静态知识图谱升级为动态业务引擎。通过引入函数和行动作为核心元素,Ontology实现了业务逻辑的自动化响应与执行,显著提升物流、能源等领域的运营效率。文章详细解析了其混合存储引擎、状态监听网络等关键技术设计,并对比展示了传统架构与Ontology架构的业务价值差异。

weixin_42570296的博客 200

SAP BASIS运维之三方SSL证书导入

事情的起因是我司SAP使用的SSL证书即将要到期了(上一个的SAP BASIS也辞职了),需要进行证书的更换。如上图所示,我司的证书有效期到2024年4月30日到期,需要提前预防并更换,防止过期后导致接口和访问出现问题。9.在弹出的框中,选择我们在第5个步骤中导出的转换结果存储地址,并选择导出的转换文件,点打开。12.最后一步也是关键的一步,不然就会无法更新证书,再点击左上角的个人安全环境,点另存为。10.在打开后的弹窗中,输入我们在第4个步骤中设置的密码。6.经过以上步骤后,我们获得了最终的证书文件。

fegda的专栏 1884

Learning Golang项目全解析:从零基础到实战高手的完整指南

Learning Golang项目是一个全面的Go语言学习资源,提供了丰富的实战示例、算法实现和真实世界应用案例,帮助开发者从零基础掌握Go语言的基础和高级特性。无论是刚入门的新手还是有一定经验的开发者,都能通过这个项目快速提升Go编程技能。 ## 为什么选择Learning Golang项目? Go语言作为近年来备受关注的编程语言,以其简洁高效、并发性能优越和强大的标准库而闻名。Learni

gitblog_00057的博客 323

SD卡烧写Linux kernel——SD卡分区,并烧写uboot,kernel,DTB及filesystem

Linux Ubuntu环境下对SD卡分区(烧写uboot,kernel,及filesystem) 介绍dd命令的使用,SD卡分区、格式化、复制文件等 fdisk命令

weixin_42408707的博客 5056

cgo c数组_Go语言学习之cgo(golang与C语言相互调用)

原标题:Go语言学习之cgo(golang与C语言相互调用)几乎所有的编程语言都有C语言的影子,当然golang也不例外。可以看到golang的创始者们与c language有着密切的联系。所有,golang和c语言的相互调用也是理所应当。什么场合会使用Go与C的互操作呢?下面的地址给出这样的答案:http://tonybai.com/2012/09/26/interoperability-bet...

weixin_30262217的博客 1063

使用Simulink对固定翼无人机的自动起飞与降落进行仿真

本文介绍了基于Simulink的固定翼无人机自动起飞与降落控制系统设计方法。系统包含飞行器动力学模型、控制系统、环境模拟等模块,通过简化动力学方程描述无人机运动特性。详细说明了从创建模型、设置动力学方程、设计PID控制器(包括自动起飞和降落控制策略)到添加环境模拟的完整仿真流程。重点阐述了升降舵和发动机推力的控制律设计,以及性能评估要点。本方法可有效验证控制系统设计,优化飞行稳定性和安全性参数,为无人机自主控制提供仿真支持。

amy_mhd的博客 223

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

golang 相互引用_Go语言学习之cgo(golang与C语言相互调用)

几乎所有的编程语言都有C语言的影子,当然golang也不例外。可以看到golang的创始者们与c language有着密切的联系。所有,golang和c语言的相互调用也是理所应当。什么场合会使用Go与C的互操作呢?下面的地址给出这样的答案:http://tonybai.com/2012/09/26/interoperability-between-go-and-c/1、提升局部代码性能时,用...

weixin_33989001的博客 600

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

7天精通Go语言:over-golang从入门到实战的完整学习路径

Go语言作为近年来备受瞩目的编程语言,凭借其简洁高效、原生支持并发和强大的性能表现,成为云计算、微服务和后端开发的首选语言。over-golang项目提供了一套系统全面的Go语言学习资料,涵盖从基础语法到高级微服务开发的完整知识体系。本文将为你详细规划一条高效的学习路径,帮助你在最短时间内掌握Go语言核心技能。 ## 一、为什么选择Go语言? Go语言由Google开发并于2009年正式发布,

gitblog_00794的博客 877

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

WINCC7.3破解文件

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

【Go语言-Day 15】玩转 Go Map:从 for range 遍历到 delete 删除的终极指南

本文是 Go 语言学习系列的第 15 篇,将深入探讨 `map` 类型的进阶操作。继上一篇我们掌握了 `map` 的创建和基本增改查之后,本篇将聚焦于 `map` 的两大核心操作:如何安全地删除键值对,以及如何高效地遍历 `map`。我们将通过丰富的代码示例,详细解析 `delete()` 函数的使用、`for...range` 遍历的特性及其无序性原理。

吴师兄大模型的博客 1257

Go 专栏|接口 interface,Golang端简单易用的SPI框架

本文从鸭子类型引出 Go 的接口,然后用一个例子简单展示了接口类型的用法,接着又介绍了接口赋值,空接口,类型断言和类型查询。相信通过本篇文章大家能对接口有了整体的概念,并掌握了基本用法。文章中的脑图和源码都上传到了 GitHub,有需要的同学可自行下载。开发环境搭建以及开发工具 VS Code 配置变量和常量的声明与赋值基础数据类型:整数、浮点数、复数、布尔值和字符串网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

2401_84301352的博客 988

合集 | Go 语言学习笔记目录

合集 | Go 语言学习笔记目录

Wonz 639

Go语言学习

Go学习该go语言的依赖管理 接口,函数式编程,CSP并发模型 基本语法 该给给 # 镜像下载地址 GOPROXY=https://proxy.golang.org,direct # 更换到国内网址 go env -w GOPROXY=https://goproxy.cn,direct go env -w GO111MODULE=on # 验证仓库是否好使 go get -v golang....

qq_30923243的博客 327

计算机基础语言学习线路图

计算机基础语言学习线路图 HTML HTML教程 HTML简介 HTML编辑器 HTML基础 HTML元素 HTML属性 HTML标题 HTML段落 HTML样式 HTML格式化 HTML引用元素 HTML计算机代码元素 HTML注释 HTML颜色 HTML和样式表 HTML超链接 HTML图片 HTML表格 HTML列表 HTML块级元素 HTML类 HTML iframe...

hixiaoyang的博客 3264

go语言学习总结,有源码有注释

第一章、go语言基础数据类型,01_基础数据类型1 变量的声明,变量初始化,变量赋值,匿名变量,iota枚举 第一章、go语言基础数据类型,02_基础数据类型2 float,bool,byte,string,复数类型,格式化输出,变量的输入,类型转换,类型别名type 第二章、go语言流程控制,03_流程控制 if语句,switch语句,for循环,range迭代,break,continue,goto 第三章、go语言函数,04_函数的使用1 无参、有参,无返回值、有返回值函数的定义和使用,不定参数函数,

weixin_40355471的博客 1357

【Go语言-Day 19】深入理解Go自定义类型:Type、Struct、嵌套与构造函数实战

文章将从 `type` 关键字的基础用法(类型别名与新类型定义)切入,逐步引导读者掌握 `struct` 的定义、多种实例化方法、字段访问、以及匿名结构体和嵌套等高级技巧。最后,我们将讨论构造函数(工厂函数)这一重要的编程模式,帮助你编写出更健壮、更具可维护性的 Go 代码。无论你是 Go 新手还是希望巩固基础的开发者,本文都将为你提供清晰的指引和丰富的实战代码。

吴师兄大模型的博客 1067

Go语言学习笔记----与C语言的比较学习

最近学习了golang(go语言),其中大部分是和C相似的,记录一下不同的地方,需要注意1.go的左花括号“{”不能单独放在一行 出错代码:package main import "fmt" func main() { //error, can't have the opening brace on a separate line fmt.Println("hello there!")

caisense的专栏 4987

【Go语言-Day 38】编写地道Go代码:Go语言官方代码规范与最佳实践深度解析

本文是 Go 语言学习系列的第 38 篇,旨在全面、深入地探讨 Go 语言的代码规范与编程风格。编写符合社区共识的“地道”Go 代码,不仅能极大提升代码的可读性和可维护性,更是专业 Go 工程师的必备技能。本文将从自动化格式工具 `gofmt` 和 `goimports` 的使用,到包、变量、函数、接口的命名规范,再到注释和错误处理的最佳实践,为您提供一份详尽的 Go 代码风格指南,帮助您写出让同事赞不绝口的高质量代码。

吴师兄大模型的博客 994
上一篇: 【Go语言学习系列08】Go基础语法(六):结构体
下一篇: 【Go语言学习系列10】Go基础语法(八):接口
Gopher部落
博客等级 码龄2年 784粉丝 92原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gopher部落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值