在Go语言里,我们可以通过type关键字定义新的类型,自定义字符串类型本质是基于内置string类型创建的新类型,二者在类型系统中属于完全不同的类型,无法直接赋值或者参与运算,因此掌握二者的转换方法非常重要。
自定义字符串类型的定义
首先我们来看如何定义自定义字符串类型,最常见的定义方式如下:
// 定义自定义字符串类型 MyString,基于内置string类型
type MyString string
// 也可以给自定义类型添加方法,比如校验字符串长度
func (m MyString) IsValid() bool {
return len(m) > 0
}
这里的MyString就是自定义字符串类型,虽然它的底层存储结构和内置string一致,但是Go语言是强类型语言,MyString和string不能直接通用。
自定义字符串类型转内置字符串类型
自定义字符串类型转换为内置string类型非常简单,直接使用类型转换语法即可,因为二者的底层结构完全一致,转换过程不会额外分配内存,只是类型的重新解释。
package main
import "fmt"
type MyString string
func main() {
var ms MyString = "hello world"
// 将自定义字符串类型转换为内置string类型
s := string(ms)
fmt.Println(s) // 输出:hello world
fmt.Printf("ms type: %Tn", ms) // 输出:ms type: main.MyString
fmt.Printf("s type: %Tn", s) // 输出:s type: string
}
内置字符串类型转自定义字符串类型
反过来,将内置string类型转换为自定义字符串类型同样使用类型转换语法,转换过程也不会产生额外的内存开销,只是修改了变量的类型标识。
package main
import "fmt"
type MyString string
func main() {
s := "test string"
// 将内置string类型转换为自定义字符串类型
ms := MyString(s)
fmt.Println(ms) // 输出:test string
fmt.Printf("s type: %Tn", s) // 输出:s type: string
fmt.Printf("ms type: %Tn", ms) // 输出:ms type: main.MyString
}
转换注意事项
- 只有底层类型相同的自定义类型和内置类型才能直接转换,比如自定义类型是
type MyString string才能和string互转,如果是type MyString []byte则无法直接转换为string。 - 转换过程不会修改原始字符串的内容,只是改变变量的类型,因此转换是安全的,不会出现数据丢失的情况。
- 自定义类型的方法不会随着转换传递给内置类型,比如上面的
IsValid方法是MyString类型的,转换为string之后就无法调用该方法。
实际开发场景示例
在实际开发中,我们经常会用自定义字符串类型来做枚举值,比如定义用户角色:
package main
import "fmt"
// 定义角色类型
type Role string
// 定义角色枚举值
const (
RoleAdmin Role = "admin"
RoleUser Role = "user"
RoleGuest Role = "guest"
)
func CheckRole(r Role) {
// 将自定义角色类型转换为string进行判断
roleStr := string(r)
switch roleStr {
case "admin":
fmt.Println("当前是管理员角色")
case "user":
fmt.Println("当前是普通用户角色")
default:
fmt.Println("未知角色")
}
}
func main() {
CheckRole(RoleAdmin) // 输出:当前是管理员角色
// 也可以直接将string转换为Role类型传入
CheckRole(Role("user")) // 输出:当前是普通用户角色
}
通过这种方式,我们可以让代码中的角色参数有更明确的类型约束,避免传入非法的字符串,同时需要用到字符串值的时候也可以快速转换为内置string类型。