golang简化基本类型可选字段创建的辅助工具插件库pointer的使用

Golang简化基本类型可选字段创建的辅助工具插件库pointer的使用

概述

pointer是一个帮助简化创建基本类型可选字段的Golang工具库。它提供了一系列辅助函数来创建各种基本类型的指针,使得在结构体字面量或变量中设置指针类型字段变得更加方便。

安装

go get github.com/xorcare/pointer

使用泛型(Go 1.18+)

从Go 1.18开始,你可以使用Of方法来获取任何类型值的指针:

package pointer

// Of是一个辅助函数,分配一个新的any值来存储v并返回其指针
func Of[Value any](v Value) *Value {
    return &v
}

完整示例

package main

import (
	"fmt"
	"time"
	"github.com/xorcare/pointer"
)

type Config struct {
	Enabled *bool
	Timeout *time.Duration
	Port    *int
	Name    *string
}

func main() {
	// 使用pointer库创建配置
	config := Config{
		Enabled: pointer.Bool(true),
		Timeout: pointer.Duration(30 * time.Second),
		Port:    pointer.Int(8080),
		Name:    pointer.String("my-app"),
	}

	// 打印配置
	fmt.Printf("Enabled: %v\n", *config.Enabled)
	fmt.Printf("Timeout: %v\n", *config.Timeout)
	fmt.Printf("Port: %d\n", *config.Port)
	fmt.Printf("Name: %s\n", *config.Name)
}

常见问题解答

问题 示例代码
如何在结构体字面量或变量中设置bool指针? var _ *bool = pointer.Bool(true)
如何在结构体字面量或变量中设置byte指针? var _ *byte = pointer.Byte(1)
如何在结构体字面量或变量中设置complex64指针? var _ *complex64 = pointer.Complex64(1.1)
如何在结构体字面量或变量中设置complex128指针? var _ *complex128 = pointer.Complex128(1.1)
如何在结构体字面量或变量中设置float32指针? var _ *float32 = pointer.Float32(1.1)
如何在结构体字面量或变量中设置float64指针? var _ *float64 = pointer.Float64(1.1)
如何在结构体字面量或变量中设置int指针? var _ *int = pointer.Int(1)
如何在结构体字面量或变量中设置int8指针? var _ *int8 = pointer.Int8(8)
如何在结构体字面量或变量中设置int16指针? var _ *int16 = pointer.Int16(16)
如何在结构体字面量或变量中设置int32指针? var _ *int32 = pointer.Int32(32)
如何在结构体字面量或变量中设置int64指针? var _ *int64 = pointer.Int64(64)
如何在结构体字面量或变量中设置rune指针? var _ *rune = pointer.Rune(1)
如何在结构体字面量或变量中设置string指针? var _ *string = pointer.String("ptr")
如何在结构体字面量或变量中设置uint指针? var _ *uint = pointer.Uint(1)
如何在结构体字面量或变量中设置uint8指针? var _ *uint8 = pointer.Uint8(8)
如何在结构体字面量或变量中设置uint16指针? var _ *uint16 = pointer.Uint16(16)
如何在结构体字面量或变量中设置uint32指针? var _ *uint32 = pointer.Uint32(32)
如何在结构体字面量或变量中设置uint64指针? var _ *uint64 = pointer.Uint64(64)
如何在结构体字面量或变量中设置time.Time指针? var _ *time.Time = pointer.Time(time.Now())
如何在结构体字面量或变量中设置time.Duration指针? var _ *time.Duration = pointer.Duration(time.Hour)

替代方案

作者建议,对于Go 1.18+项目,可以考虑在项目中创建一个本地副本而不是依赖这个库。例如,可以在internal/pointer/pointer.go文件中添加以下代码:

package pointer

// Of是一个辅助函数,分配一个新的any值来存储v并返回其指针
func Of[Value any](v Value) *Value {
    return &v
}

许可证

© 2019-2020,2022 Vasiliy Vasilyuk

基于BSD 3-Clause许可证发布。


更多关于golang简化基本类型可选字段创建的辅助工具插件库pointer的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang简化基本类型可选字段创建的辅助工具插件库pointer的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 可选字段辅助工具 - pointer 库使用指南

在 Go 语言中,处理可选字段时通常需要使用指针类型,但直接使用指针语法会让代码变得冗长。pointer 库是一个简化基本类型可选字段创建的辅助工具,它可以帮助我们更简洁地创建基本类型的指针。

安装 pointer 库

go get github.com/AlekSi/pointer

基本使用方法

pointer 库提供了 To 系列函数来创建各种基本类型的指针:

package main

import (
	"fmt"
	"github.com/AlekSi/pointer"
)

func main() {
	// 创建各种基本类型的指针
	intPtr := pointer.ToInt(42)
	floatPtr := pointer.ToFloat64(3.14)
	stringPtr := pointer.ToString("hello")
	boolPtr := pointer.ToBool(true)
	
	fmt.Println(*intPtr)    // 输出: 42
	fmt.Println(*floatPtr)  // 输出: 3.14
	fmt.Println(*stringPtr) // 输出: hello
	fmt.Println(*boolPtr)   // 输出: true
}

主要功能

1. 创建指针

pointer 库支持所有基本类型的指针创建:

// 整数类型
i8 := pointer.ToInt8(8)
i16 := pointer.ToInt16(16)
i32 := pointer.ToInt32(32)
i64 := pointer.ToInt64(64)

// 无符号整数类型
u8 := pointer.ToUint8(8)
u16 := pointer.ToUint16(16)
u32 := pointer.ToUint32(32)
u64 := pointer.ToUint64(64)

// 浮点数
f32 := pointer.ToFloat32(3.14)
f64 := pointer.ToFloat64(3.1415926)

// 其他类型
str := pointer.ToString("golang")
b := pointer.ToBool(true)
t := pointer.ToTime(time.Now())

2. 获取指针值或默认值

package main

import (
	"fmt"
	"github.com/AlekSi/pointer"
)

func main() {
	var nilInt *int
	
	// 获取指针值,如果为nil则返回默认值
	v1 := pointer.GetInt(nilInt)       // 返回 0
	v2 := pointer.GetInt(nilInt, 42)   // 返回 42
	
	fmt.Println(v1, v2)
}

3. 比较指针值

package main

import (
	"fmt"
	"github.com/AlekSi/pointer"
)

func main() {
	a := pointer.ToInt(10)
	b := pointer.ToInt(10)
	c := pointer.ToInt(20)
	
	fmt.Println(pointer.Equal(a, b)) // true
	fmt.Println(pointer.Equal(a, c)) // false
}

4. 解引用指针

package main

import (
	"fmt"
	"github.com/AlekSi/pointer"
)

func main() {
	var nilInt *int
	val := pointer.Deref(nilInt, 100) // 如果nilInt为nil,返回100
	
	fmt.Println(val) // 输出: 100
}

实际应用示例

结构体中的可选字段

package main

import (
	"fmt"
	"github.com/AlekSi/pointer"
)

type User struct {
	ID        int
	Name      string
	Age       *int      // 可选字段
	IsActive  *bool     // 可选字段
	LastLogin *string   // 可选字段
}

func main() {
	// 创建用户,只设置必填字段
	user1 := User{
		ID:   1,
		Name: "Alice",
	}
	
	// 创建用户,设置所有字段
	user2 := User{
		ID:        2,
		Name:      "Bob",
		Age:       pointer.ToInt(30),
		IsActive:  pointer.ToBool(true),
		LastLogin: pointer.ToString("2023-01-01"),
	}
	
	fmt.Printf("%+v\n", user1)
	fmt.Printf("%+v\n", user2)
	
	// 安全访问可选字段
	age := pointer.GetInt(user1.Age, -1) // 返回-1,因为Age是nil
	fmt.Println("Alice's age:", age)
}

JSON 序列化/反序列化

package main

import (
	"encoding/json"
	"fmt"
	"github.com/AlekSi/pointer"
)

type Config struct {
	Host     string
	Port     *int    `json:"port,omitempty"`
	Timeout  *int    `json:"timeout,omitempty"`
	Debug    *bool   `json:"debug,omitempty"`
}

func main() {
	// 序列化
	cfg := Config{
		Host:    "localhost",
		Port:    pointer.ToInt(8080),
		Debug:   pointer.ToBool(false),
		// Timeout 保持nil
	}
	
	data, _ := json.MarshalIndent(cfg, "", "  ")
	fmt.Println(string(data))
	
	// 反序列化
	jsonStr := `{"host":"example.com","timeout":30}`
	var cfg2 Config
	json.Unmarshal([]byte(jsonStr), &cfg2)
	
	fmt.Printf("%+v\n", cfg2)
	fmt.Println("Port is set:", cfg2.Port != nil) // false
	fmt.Println("Timeout:", pointer.GetInt(cfg2.Timeout)) // 30
}

总结

pointer 库的主要优点:

  1. 简化了基本类型指针的创建语法
  2. 提供了安全的指针解引用方法
  3. 支持指针值的比较
  4. 特别适合处理结构体中的可选字段
  5. 与 JSON 序列化/反序列化配合良好

相比直接使用 & 操作符创建指针,pointer 库的代码更清晰易读,特别是在处理大量可选字段时能显著提高代码的可维护性。

回到顶部