Golang中何时使用"type"而非"var"进行声明

Golang中何时使用"type"而非"var"进行声明 大家好,

我正在学习Go语言,对编程也比较陌生。 我想从原理和时机上理解我的问题。

在一个教程中,我看到了下面的代码…

var a int          // 创建一个名为a的变量
type a int       // 创建一个名为a的int类型

我在多个地方都注意到了类似的模式。我们什么时候需要创建变量,什么时候需要创建类型呢?

提前感谢。

4 回复

变量可以持有给定类型的值。

类型描述了值允许以何种形式呈现。

更多关于Golang中何时使用"type"而非"var"进行声明的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


vinayak.vg:

type a int

通常,当你希望确保用于不同目的的整数(在本例中)不会被意外混淆时,你会像上面那样定义一个类型。

补充一下这里的回答:你可以通过定义类型来为更基础的类型赋予额外的含义。例如,在标准库中,byte 只是 uint8 的别名——但对开发者而言,byte 具有不同的含义。以下是我经常处理的一个实际场景,其中可能涉及不同的云服务提供商。为我的提供商(或其他任何内容)声明一个类型:

// 块存储提供商
type BlockStorageProvider uint8

// 块存储提供商选项
const (
	AWS BlockStorageProvider = iota
	GoogleCloud
	Azure
)

…这使得该函数中的预期用途更加明显:

func doSomething(provider BlockStorageProvider) {
	// 实际上,这可能会返回一个客户端或执行某些操作
	switch provider {
	case AWS:
		fmt.Println("正在使用 AWS 执行操作")
	case GoogleCloud:
		fmt.Println("正在使用 Google Cloud 执行操作")
	case Azure:
		fmt.Println("正在使用 Azure 执行操作")
	default:
		fmt.Println("未知提供商:", provider)
	}
}

我本可以只传入一个 uint8 并附注说明选项在常量中查找,但通过声明一个类型,我为 uint8 赋予了额外的含义。就像 byte 在我心中与 uint8 含义不同,即使它们是同一事物。查看更多示例,请查看 Go 源代码:

https://cs.opensource.google/go/go/+/refs/tags/go1.19.1:src/go/types/basic.go;l=43

如你所见,byte 的类型是 BasicKind,而 BasicKind 本身只是一个 int,例如:

// BasicKind 描述了基本类型的种类。
type BasicKind int

在Go语言中,vartype用于完全不同的目的,理解它们的区别对编写正确的Go代码至关重要。

核心区别

var 用于声明变量(分配内存空间):

var count int        // 声明一个int类型的变量count,默认值为0
var name string      // 声明一个string类型的变量name,默认值为""
var active bool      // 声明一个bool类型的变量active,默认值为false

type 用于创建新的类型别名或定义新类型:

type Celsius float64    // 创建新类型Celsius,底层是float64
type ID string          // 创建新类型ID,底层是string
type Counter int        // 创建新类型Counter,底层是int

何时使用type

1. 增加类型安全性(主要用途)

type UserID int
type ProductID int

func GetUser(id UserID) {
    // 只能接受UserID类型
}

func main() {
    var uid UserID = 100
    var pid ProductID = 100
    
    GetUser(uid)     // 正确
    GetUser(pid)     // 编译错误:类型不匹配
    // 即使底层都是int,但UserID和ProductID是不同的类型
}

2. 为现有类型添加方法

type Celsius float64

// 为Celsius类型添加方法
func (c Celsius) ToFahrenheit() Fahrenheit {
    return Fahrenheit(c*9/5 + 32)
}

func (c Celsius) String() string {
    return fmt.Sprintf("%.1f°C", c)
}

func main() {
    var temp Celsius = 25.5
    fmt.Println(temp)               // 25.5°C
    fmt.Println(temp.ToFahrenheit()) // 77.9°F
}

3. 提高代码可读性

// 不使用type
func Process(data []map[string]interface{}) {
    // 参数类型难以理解
}

// 使用type
type UserData map[string]interface{}
type UserList []UserData

func Process(users UserList) {
    // 参数含义清晰
}

4. 定义结构体、接口等复合类型

// 定义结构体
type Person struct {
    Name string
    Age  int
}

// 定义接口
type Reader interface {
    Read(p []byte) (n int, err error)
}

// 定义函数类型
type HandlerFunc func(http.ResponseWriter, *http.Request)

实际示例对比

// 使用var声明变量
var count int = 10
var total float64 = 99.99
var username string = "john"

// 使用type创建新类型
type Quantity int
type Price float64
type Username string

// 使用新类型声明变量
var qty Quantity = 10
var cost Price = 99.99
var user Username = "john"

// 为Username类型添加方法
func (u Username) IsValid() bool {
    return len(u) >= 3 && len(u) <= 20
}

// 使用
fmt.Println(user.IsValid()) // true

关键原则

  1. 需要存储数据 → 使用var声明变量
  2. 需要创建新类型(添加方法、提高类型安全、定义结构体等) → 使用type
  3. 即使底层类型相同,通过type创建的类型也是不同的类型,不能直接混用
  4. 类型转换是显式的:Quantity(10)int(qty)

在教程中看到的type a int创建了一个名为a的新类型,而var a int创建了一个名为a的变量。它们虽然名字相同,但一个是类型名,一个是变量名,在不同的命名空间中。

回到顶部