为简明起见,我们以一个简单的问题为例:1 米加 1 英尺等于多少米?,来看看 Go 语言如何处理这种计量单位不一致的问题。

这个问题的本质在于,一旦使用原始类型(如 float64int 等)表示长度、时间、重量等带单位的数值,就极易导致单位混淆——不小心将“1 米”和“1 英尺”直接相加,算出 2 米,犯个低级错误。因此,关键在于如何巧妙地利用 Go 的类型系统,在编译阶段就杜绝这类失误。

一种方法是通过 类型别名(type 自定义类型) 来模拟计量单位。

// https://go.dev/play/p/Ui2UzlrZrA1
package main

import "fmt"

// 自定义类型:以 float64 为底层类型
type Meter float64
type Foot float64

// 定义转换常量
const footToMeter = 0.3048

// 为 Foot 添加 ToMeter 方法,Foot -> Meter 的转换方法
func (f Foot) ToMeter() Meter {
    return Meter(float64(f) * footToMeter)
}

func main() {
    var m Meter = 1.0
    var f Foot = 1.0

    // 即使底层都是 float64,也不能直接将 Meter 和 Foot 相加
    // result := m + f 
    // 错误❌:invalid operation: m + f (mismatched types Meter and Foot)

    // 正确✅:先将 Foot 转为 Meter
    result := m + f.ToMeter()
    fmt.Printf("1 米 + 1 英尺 = %.4f 米\n", result)
    // 1 米 + 1 英尺 = 1.3048 米
}

但由于类型别名的底层都是相同的基础类型 float64,因此通过类型转换,还是有机会计算出错误的结果:

errorResult := float64(m) + float64(f)
fmt.Printf("1 米 + 1 英尺 = %.4f 米\n", errorResult) 
// 错误❌:1 米 + 1 英尺 = 2.0000 米

还有一种方法可用于处理计量单位不一致的问题,方法灵感来自 Go 标准库中的 time.Duration 类型。通过自定义类型 + 单位常量 + 乘法赋与单位的组合,即可实现可读性更强的数值操作方式:

// https://go.dev/play/p/UeOGbN2j9zK
package main

import (
    "fmt"
)

// 定义一个新类型 Length,底层是 float64,用于表示带单位的长度
type Length float64

// 定义单位常量,米为基准长度单位
const (
    Meter Length = 1.0    // 米,作为长度的基准单位
    Foot  Length = 0.3048 // 英尺,等于 0.3048 米
)

// 为 Length 类型定义一个方法,用于以米为单位输出数值
func (l Length) Meter() float64 {
    return float64(l)
}

func main() {
    m := 1 * Meter
    f := 1 * Foot

    // 将两个长度相加
    result := m + f

    fmt.Printf("1 米 + 1 英尺 = %.4f 米\n", result.Meter())
    // 1 米 + 1 英尺 = 1.3048 米
}

但这种方法也有缺点,当长度存放在变量中,而不是通过字面量给出时,就不得不做类型转换,反倒降低了可读性:

func main() {
    // 用户输入或从其他函数获取的原始值(没有明确给出单位,但已知单位是米)
    m := 1.0
    f := 1 * Foot

    // 将两个长度相加
    // result := m + f
    // 错误❌:invalid operation: m + f (mismatched types float64 and Length)

    // 正确✅:必须显式转换 float64 → Length
    result := Length(m)*Meter + f

    fmt.Printf("1 米 + 1 英尺 = %.4f 米\n", result.Meter())
}

这也是使用自定义类型 + 单位常量 + 乘法赋与单位这一“组合拳”的权衡点之一。

🔚


da_miao_zi
1 声望0 粉丝

软件工程师、技术图书译者。译有《图解云计算架构》《图解量子计算机》《计算机是怎样跑起来的》《自制搜索引擎》等。