numx

package
v1.0.0-alpha.25 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 4, 2026 License: MIT Imports: 5 Imported by: 0

README

numx

数字类型扩展包,提供 JSON 安全的大数字类型,解决 JavaScript 精度丢失问题。

问题背景

JavaScript 的 Number.MAX_SAFE_INTEGER9007199254740991(2^53 - 1),超过这个范围的整数会丢失精度。后端常用的 int64 类型范围远大于此,导致前后端数据交互时出现精度问题。

解决方案

numx 包提供了几种类型,在 JSON 序列化时自动转换为字符串,避免精度丢失:

  • ID: int64 类型别名,用于数据库主键
  • BigInt: 通用的 int64 包装
  • BigUint: uint64 包装
  • Timestamp: int64 时间戳(毫秒)

安装

go get github.com/whl/gocrud/csgo/numx

使用示例

基本使用
package main

import (
    "encoding/json"
    "fmt"
    "github.com/whl/gocrud/csgo/numx"
)

type User struct {
    ID        numx.ID        `json:"id"`
    Score     numx.BigInt    `json:"score"`
    Views     numx.BigUint   `json:"views"`
    CreatedAt numx.Timestamp `json:"created_at"`
}

func main() {
    user := User{
        ID:        9007199254740992, // 超过 JS 安全整数范围
        Score:     -123456789012345,
        Views:     18446744073709551615, // uint64 最大值
        CreatedAt: numx.Now(),
    }

    // JSON 序列化
    data, _ := json.Marshal(user)
    fmt.Println(string(data))
    // 输出: {"id":"9007199254740992","score":"-123456789012345","views":"18446744073709551615","created_at":"1703234567890"}

    // JSON 反序列化(支持 string 和 number 两种格式)
    jsonStr := `{"id":"123","score":-456,"views":"789","created_at":"1703234567890"}`
    var u User
    json.Unmarshal([]byte(jsonStr), &u)
    fmt.Printf("%+v\n", u)
}
数据库操作

所有类型都实现了 sql.Scannerdriver.Valuer 接口,可直接用于数据库操作:

type Article struct {
    ID        numx.ID        `db:"id" json:"id"`
    AuthorID  numx.ID        `db:"author_id" json:"author_id"`
    Views     numx.BigUint   `db:"views" json:"views"`
    CreatedAt numx.Timestamp `db:"created_at" json:"created_at"`
}

// 数据库查询
var article Article
db.QueryRow("SELECT id, author_id, views, created_at FROM articles WHERE id = ?", 123).
    Scan(&article.ID, &article.AuthorID, &article.Views, &article.CreatedAt)

// 数据库插入
db.Exec("INSERT INTO articles (id, author_id, views, created_at) VALUES (?, ?, ?, ?)",
    article.ID, article.AuthorID, article.Views, article.CreatedAt)
类型转换
id := numx.ID(123456)

// 转换为基础类型
i := id.Int64()        // int64
s := id.String()       // "123456"
isZero := id.IsZero()  // false

// Timestamp 特有方法
ts := numx.Now()
t := ts.Time()         // time.Time
ts2 := numx.FromTime(time.Now())
Web API 示例
// 请求
type CreateUserRequest struct {
    Name      string     `json:"name"`
    ParentID  numx.ID    `json:"parent_id"`  // 前端传 "123" 或 123
}

// 响应
type UserResponse struct {
    ID        numx.ID        `json:"id"`         // 输出 "9007199254740992"
    Name      string         `json:"name"`
    CreatedAt numx.Timestamp `json:"created_at"` // 输出 "1703234567890"
}

func CreateUser(w http.ResponseWriter, r *http.Request) {
    var req CreateUserRequest
    json.NewDecoder(r.Body).Decode(&req)
    
    // req.ParentID 自动解析为 int64
    user := User{
        ID:        numx.ID(generateID()),
        Name:      req.Name,
        ParentID:  req.ParentID,
        CreatedAt: numx.Now(),
    }
    
    // 自动序列化为字符串
    json.NewEncoder(w).Encode(UserResponse{
        ID:        user.ID,
        Name:      user.Name,
        CreatedAt: user.CreatedAt,
    })
}

API 文档

ID
type ID int64

// JSON 序列化方法
func (id ID) MarshalJSON() ([]byte, error)
func (id *ID) UnmarshalJSON(data []byte) error

// 数据库方法
func (id ID) Value() (driver.Value, error)
func (id *ID) Scan(value interface{}) error

// 辅助方法
func (id ID) Int64() int64
func (id ID) String() string
func (id ID) IsZero() bool
BigInt
type BigInt int64

// 方法同 ID,不含 IsZero
BigUint
type BigUint uint64

func (b BigUint) Uint64() uint64
func (b BigUint) String() string
// 其他方法同上
Timestamp
type Timestamp int64

// 额外方法
func (t Timestamp) Time() time.Time
func Now() Timestamp
func FromTime(t time.Time) Timestamp

JSON 序列化示例

Go 类型 Go 值 JSON 输出 JSON 输入(支持)
numx.ID 123 "123" "123"123
numx.BigInt -456 "-456" "-456"-456
numx.BigUint 789 "789" "789"789
numx.Timestamp 1703234567890 "1703234567890" "1703234567890"1703234567890

注意事项

  1. 反序列化兼容性: 所有类型都支持从 JSON string 和 number 两种格式反序列化,确保前后端兼容
  2. 数据库兼容性: 在数据库中存储为原生的 int64/uint64,无额外开销
  3. 类型安全: 保留所有原生类型的运算和比较能力
  4. 零值判断: ID 类型提供 IsZero() 方法,方便判断是否为默认值

测试

cd numx
go test -v

License

MIT

Documentation

Overview

Example

Example demonstrates basic usage of numx types

package main

import (
	"encoding/json"
	"fmt"

	"github.com/gocrud/csgo/x/numx"
)

func main() {
	type User struct {
		ID        numx.ID        `json:"id"`
		Score     numx.BigInt    `json:"score"`
		Views     numx.BigUint   `json:"views"`
		CreatedAt numx.Timestamp `json:"created_at"`
	}

	user := User{
		ID:        9007199254740992, // Greater than JavaScript's MAX_SAFE_INTEGER
		Score:     -123456789012345,
		Views:     18446744073709551,
		CreatedAt: numx.Now(),
	}

	// Marshal to JSON - numbers become strings
	data, _ := json.Marshal(user)
	fmt.Printf("JSON: %s\n", data)

	// Unmarshal from JSON - accepts both string and number
	jsonStr := `{"id":"123","score":-456,"views":"789","created_at":"1703234567890"}`
	var u User
	json.Unmarshal([]byte(jsonStr), &u)
	fmt.Printf("User ID: %d, Score: %d\n", u.ID.Int64(), u.Score.Int64())
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BigInt

type BigInt int64

BigInt 是一个 int64 类型,在 JSON 序列化/反序列化时作为字符串处理,以避免在 JavaScript 中丢失精度。

func (BigInt) Int64

func (b BigInt) Int64() int64

Int64 将 BigInt 转换为 int64。

func (BigInt) MarshalJSON

func (b BigInt) MarshalJSON() ([]byte, error)

MarshalJSON 实现 json.Marshaler 接口。

func (BigInt) String

func (b BigInt) String() string

String 返回 BigInt 的字符串表示。

func (*BigInt) UnmarshalJSON

func (b *BigInt) UnmarshalJSON(data []byte) error

UnmarshalJSON 实现 json.Unmarshaler 接口。

type BigUint

type BigUint uint64

BigUint 是一个 uint64 类型,在 JSON 序列化/反序列化时作为字符串处理,以避免在 JavaScript 中丢失精度。

func (BigUint) MarshalJSON

func (b BigUint) MarshalJSON() ([]byte, error)

MarshalJSON 实现 json.Marshaler 接口。

func (BigUint) String

func (b BigUint) String() string

String 返回 BigUint 的字符串表示。

func (BigUint) Uint64

func (b BigUint) Uint64() uint64

Uint64 将 BigUint 转换为 uint64。

func (*BigUint) UnmarshalJSON

func (b *BigUint) UnmarshalJSON(data []byte) error

UnmarshalJSON 实现 json.Unmarshaler 接口。

type ID

type ID int64

ID is an int64 type that serializes to/from JSON as a string to avoid precision loss in JavaScript.

Example

ExampleID demonstrates ID type usage

package main

import (
	"encoding/json"
	"fmt"

	"github.com/gocrud/csgo/x/numx"
)

func main() {
	id := numx.ID(9007199254740992)

	// JSON serialization
	data, _ := json.Marshal(id)
	fmt.Printf("JSON: %s\n", data)

	// Type conversion
	fmt.Printf("Int64: %d\n", id.Int64())
	fmt.Printf("String: %s\n", id.String())
	fmt.Printf("IsZero: %v\n", id.IsZero())

}
Output:
JSON: "9007199254740992"
Int64: 9007199254740992
String: 9007199254740992
IsZero: false

func (ID) Int64

func (id ID) Int64() int64

Int64 converts ID to int64.

func (ID) IsEmpty

func (id ID) IsEmpty() bool

func (ID) IsZero

func (id ID) IsZero() bool

IsZero returns true if ID is zero.

func (ID) MarshalJSON

func (id ID) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler interface. Converts int64 to JSON string to prevent precision loss in JavaScript.

func (ID) String

func (id ID) String() string

String returns the string representation of ID.

func (*ID) UnmarshalJSON

func (id *ID) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler interface. Accepts both JSON string and number formats.

type Timestamp

type Timestamp int64

Timestamp is an int64 Unix timestamp (milliseconds) that serializes to/from JSON as a string.

Example

ExampleTimestamp demonstrates Timestamp type usage

package main

import (
	"encoding/json"
	"fmt"

	"github.com/gocrud/csgo/x/numx"
)

func main() {
	// Create timestamp
	now := numx.Now()

	// Convert to time.Time
	t := now.Time()
	fmt.Printf("Time: %v\n", t.Format("2006-01-02"))

	// JSON serialization
	data, _ := json.Marshal(now)
	fmt.Printf("JSON: %s\n", data)
}

func FromTime

func FromTime(t time.Time) Timestamp

FromTime creates a Timestamp from time.Time (milliseconds).

func Now

func Now() Timestamp

Now returns the current time as a Timestamp (milliseconds).

func (Timestamp) Int64

func (t Timestamp) Int64() int64

Int64 converts Timestamp to int64.

func (Timestamp) MarshalJSON

func (t Timestamp) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler interface.

func (*Timestamp) Scan

func (t *Timestamp) Scan(value interface{}) error

Scan implements sql.Scanner interface.

func (Timestamp) String

func (t Timestamp) String() string

String returns the string representation of Timestamp.

func (Timestamp) Time

func (t Timestamp) Time() time.Time

Time converts Timestamp to time.Time (assumes milliseconds).

func (*Timestamp) UnmarshalJSON

func (t *Timestamp) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler interface.

func (Timestamp) Value

func (t Timestamp) Value() (driver.Value, error)

Value implements driver.Valuer interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL