跳到主要内容

cast - 类型转换库

cast 是一个简单易用的类型转换函数库,提供字符串到各种 Go 基本类型的转换功能。最低支持 Go 1.21.0 版本。

安装

go get -u go-slim.dev/cast

快速开始

package main

import (
"fmt"
"go-slim.dev/cast"
)

func main() {
// 字符串转整数
num, _ := cast.Int("42")
fmt.Println(num) // 42

// 字符串转布尔值
flag, _ := cast.Bool("true")
fmt.Println(flag) // true

// 字符串转时间
t, _ := cast.Time("2023-12-25T10:30:45Z")
fmt.Println(t)
}

Bool - 布尔值转换

函数签名

func Bool(s string) (bool, error)

说明

将字符串解析成 bool 值,内部使用标准库 strconv.ParseBool 实现。

支持的值

  • true: "1", "t", "T", "true", "TRUE", "True"
  • false: "0", "f", "F", "false", "FALSE", "False"

示例

// 返回 true
cast.Bool("true")
cast.Bool("TRUE")
cast.Bool("1")
cast.Bool("t")

// 返回 false
cast.Bool("false")
cast.Bool("FALSE")
cast.Bool("0")
cast.Bool("f")

// 返回错误
cast.Bool("yes") // 不支持的值
cast.Bool("no") // 不支持的值

Uint 系列 - 无符号整数转换

函数签名

func Uint(s string) (uint, error)
func Uint8(s string) (uint8, error)
func Uint16(s string) (uint16, error)
func Uint32(s string) (uint32, error)
func Uint64(s string) (uint64, error)

说明

将字符串解析成对应类型的无符号整数值,内部使用标准库 strconv.ParseUint 实现。

支持的格式

  • 十进制: "123"
  • 十六进制: "0x7B" (前缀 0x)
  • 八进制: "0173" (前缀 0)
  • 二进制: "0b1111011" (前缀 0b)

示例

// 十进制
num, _ := cast.Uint("123") // 123
num8, _ := cast.Uint8("255") // 255

// 十六进制
num, _ := cast.Uint("0xFF") // 255

// 八进制
num, _ := cast.Uint("0777") // 511

// 二进制
num, _ := cast.Uint("0b1010") // 10

// 超出范围会返回错误
_, err := cast.Uint8("256") // 错误:超出 uint8 范围

Int 系列 - 有符号整数转换

函数签名

func Int(s string) (int, error)
func Int8(s string) (int8, error)
func Int16(s string) (int16, error)
func Int32(s string) (int32, error)
func Int64(s string) (int64, error)

说明

将字符串解析成对应类型的有符号整数值,内部使用标准库 strconv.ParseInt 实现。

支持的格式

  • 十进制: "123", "-123"
  • 十六进制: "0x7B", "-0x7B"
  • 八进制: "0173", "-0173"
  • 二进制: "0b1111011", "-0b1111011"

示例

// 正数
num, _ := cast.Int("42") // 42

// 负数
num, _ := cast.Int("-42") // -42

// 十六进制
num, _ := cast.Int32("0xFF") // 255
num, _ := cast.Int32("-0xFF") // -255

// 超出范围会返回错误
_, err := cast.Int8("128") // 错误:超出 int8 范围 (-128 到 127)

Float 系列 - 浮点数转换

函数签名

func Float32(s string) (float32, error)
func Float64(s string) (float64, error)

说明

将字符串解析成对应类型的浮点数值,内部使用标准库 strconv.ParseFloat 实现。

示例

// 普通浮点数
num, _ := cast.Float64("3.14") // 3.14
num, _ := cast.Float64("-2.5") // -2.5

// 科学计数法
num, _ := cast.Float64("1.23e-4") // 0.000123
num, _ := cast.Float64("1E6") // 1000000

// 特殊值
num, _ := cast.Float64("Inf") // +Inf
num, _ := cast.Float64("-Inf") // -Inf
num, _ := cast.Float64("NaN") // NaN

Decimal - 高精度十进制转换

函数签名

func Decimal(s string) (decimal.Decimal, error)

说明

将字符串解析成高精度的十进制数值,使用 github.com/shopspring/decimal 包实现。适用于需要精确计算的场景,如金融计算。

示例

import "github.com/shopspring/decimal"

// 高精度计算
d1, _ := cast.Decimal("0.1")
d2, _ := cast.Decimal("0.2")
sum := d1.Add(d2) // 精确的 0.3

// 避免浮点数精度问题
// float64: 0.1 + 0.2 = 0.30000000000000004
// decimal: 0.1 + 0.2 = 0.3

Time - 时间转换

函数签名

func Time(s string) (time.Time, error)

说明

将字符串解析成 time.Time 值。支持多种常见的时间格式,包括 RFC 标准格式、常见日期格式和 Unix 时间戳。

支持的格式

  • RFC3339: "2006-01-02T15:04:05Z07:00"
  • 日期时间: "2006-01-02 15:04:05"
  • 仅日期: "2006-01-02"
  • Unix 时间戳: "1703505045" (秒)
  • 带纳秒: "2006-01-02 15:04:05.999999999"
  • 其他 RFC 格式: RFC1123, RFC822, 等

示例

// RFC3339 格式
t, _ := cast.Time("2023-12-25T10:30:45Z")

// 常见日期格式
t, _ := cast.Time("2023-12-25")
t, _ := cast.Time("2023-12-25 10:30:45")
t, _ := cast.Time("2023/12/25")

// Unix 时间戳
t, _ := cast.Time("1703505045") // 2023-12-25 10:30:45 UTC

// 美国日期格式
t, _ := cast.Time("12/25/2023")
t, _ := cast.Time("Dec 25, 2023")

// RFC 格式
t, _ := cast.Time("Mon, 02 Jan 2006 15:04:05 MST")

Duration - 时间间隔转换

函数签名

func Duration(s string) (time.Duration, error)

说明

将字符串解析成 time.Duration 值。支持多种输入格式。

支持的格式

  • Go 标准格式: "1h30m45s", "500ms", "2h"
  • 整数: 视为纳秒
  • 浮点数: 视为秒

示例

// Go 标准格式
d, _ := cast.Duration("1h30m45s") // 1 小时 30 分 45 秒
d, _ := cast.Duration("500ms") // 500 毫秒
d, _ := cast.Duration("2h") // 2 小时

// 整数(纳秒)
d, _ := cast.Duration("1000000000") // 1 秒(10 亿纳秒)

// 浮点数(秒)
d, _ := cast.Duration("1.5") // 1.5 秒
d, _ := cast.Duration("0.001") // 1 毫秒

FromString - 通用类型转换

函数签名

func FromString(s string, targetType string) (any, error)

说明

这是对所有类型转换函数的封装,根据类型名称字符串动态选择转换函数。

支持的类型名称

  • 整数: "int", "int8", "int16", "int32", "int64"
  • 无符号整数: "uint", "uint8", "uint16", "uint32", "uint64"
  • 浮点数: "float32", "float64"
  • 布尔值: "bool"
  • 字符串: "string"
  • 时间: "time.Time", "time.Duration"

示例

// 整数转换
v, _ := cast.FromString("42", "int") // int(42)
v, _ := cast.FromString("255", "uint8") // uint8(255)

// 浮点数转换
v, _ := cast.FromString("3.14", "float64") // float64(3.14)

// 布尔值转换
v, _ := cast.FromString("true", "bool") // bool(true)

// 字符串转换
v, _ := cast.FromString("hello", "string") // string("hello")

// 时间转换
v, _ := cast.FromString("2023-12-25", "time.Time")
v, _ := cast.FromString("1h30m", "time.Duration")

// 不支持的类型会返回错误
_, err := cast.FromString("42", "complex64") // 错误:不支持的类型

FromType - 基于反射的转换

函数签名

func FromType(s string, targetType reflect.Type) (any, error)

说明

该函数表示将字符串 s 转换成目标类型 targetType,并返回该类型对应的值。支持基本类型和切片类型。

切片类型支持

  • 对于切片类型(如 []int, []string),输入字符串会按逗号分割
  • 每个元素会被 trim 并转换为元素类型
  • 示例:"1,2,3"[]int{1, 2, 3}

示例

import "reflect"

// 基本类型
t := reflect.TypeOf(0)
v, _ := cast.FromType("42", t) // int(42)

// 切片类型
t := reflect.TypeOf([]int(nil))
v, _ := cast.FromType("1,2,3", t) // []int{1, 2, 3}

t := reflect.TypeOf([]string(nil))
v, _ := cast.FromType("a,b,c", t) // []string{"a", "b", "c"}

// 带空格的切片
v, _ := cast.FromType("1, 2, 3", t) // 自动 trim 空格
// 结果: []int{1, 2, 3}

使用场景

1. 配置文件解析

import "go-slim.dev/cast"

// 从环境变量或配置文件读取
port, _ := cast.Int(os.Getenv("PORT"))
debug, _ := cast.Bool(os.Getenv("DEBUG"))
timeout, _ := cast.Duration(os.Getenv("TIMEOUT"))

2. HTTP 参数处理

func handler(c slim.Context) error {
// 查询参数转换
page, err := cast.Int(c.QueryParam("page"))
if err != nil {
return c.String(400, "Invalid page number")
}

limit, _ := cast.Int(c.QueryParam("limit"))

// ... 使用 page 和 limit
}

3. 数据库值转换

// 从数据库读取的字符串值
var priceStr string
db.QueryRow("SELECT price FROM products WHERE id = ?", id).Scan(&priceStr)

// 转换为高精度 Decimal
price, _ := cast.Decimal(priceStr)

4. 命令行参数解析

import "flag"

var (
portStr = flag.String("port", "8080", "server port")
debugStr = flag.String("debug", "false", "debug mode")
)

func main() {
flag.Parse()

port, _ := cast.Int(*portStr)
debug, _ := cast.Bool(*debugStr)

// ... 使用 port 和 debug
}

错误处理

所有转换函数都返回 error,应该适当处理:

// 基本错误处理
num, err := cast.Int("abc")
if err != nil {
log.Printf("转换失败: %v", err)
return
}

// 使用默认值
num, err := cast.Int(input)
if err != nil {
num = 0 // 使用默认值
}

// 链式转换
value := "42"
if num, err := cast.Int(value); err == nil {
// 使用 num
} else {
// 处理错误
}

性能说明

  • 所有函数都是对标准库的薄包装,性能开销极小
  • 没有使用反射(除了 FromType 函数)
  • 适用于高性能场景
  • Decimal 类型会有额外的性能开销,但提供了精确的十进制运算

注意事项

  1. 类型范围检查:超出目标类型范围的值会返回错误

    _, err := cast.Uint8("256")  // 错误:超出范围 (0-255)
  2. 空字符串:大多数函数对空字符串会返回错误

    _, err := cast.Int("")       // 错误
  3. 字符串类型FromString("...", "string") 总是成功

    v, _ := cast.FromString("anything", "string")  // 总是返回原字符串
  4. 时间格式Time() 会尝试多种格式,选择第一个匹配的

    t, _ := cast.Time("2023-12-25")              // 成功
    t, _ := cast.Time("invalid") // 错误
  5. 浮点数精度:金融计算使用 Decimal 而非 Float

    // 不推荐
    f, _ := cast.Float64("0.1")

    // 推荐(金融场景)
    d, _ := cast.Decimal("0.1")

相关链接