【Golang】类型转换 - 类型断言(Type Assertion)和强制类型转换

Posted by 西维蜀黍 on 2020-03-15, Last Modified on 2021-09-21

类型断言(Type Assertion)

非安全的类型断言

package main

import "fmt"

func main() {
	var a interface{} = "ss"
	t := a.(string)
	fmt.Printf("%v", t)
}

在上面,我们将一个类型为 interface{} 的变量转换成了 string 类型。

我们可以使用类型断言(type assertion),以将一个类型为 interface{} 的变量,转换为基本数据类型或者复杂数据类型。

所谓”非安全“的类型断言,是指如果这个转换失败,则会直接在运行时报错:

package main

import "fmt"

func main() {
	var a interface{} ="ss"
	t:= a.(int)
	fmt.Printf("%d",t)

}

Error:

panic: interface conversion: interface {} is string, not int

goroutine 1 [running]:
main.main()
        /Working/GoPlayGround/main.go:7 +0x45

因此,就有了安全的类型断言。

安全的类型断言

package main

import "fmt"

func main() {
	var s interface{} = "BrainWu"
	if v, ok := s.(string); ok { // invalid type assertion: s.(string) (non-interface type string on left)
		fmt.Println(v)
	}
}

我们可以使用类型断言,将一个类型为 interface{} 的变量,转换为基本数据类型或者复杂数据类型

package main

import "fmt"

func main() {
	var a interface{} = 10
	t, ok := a.(int)
	if ok {
		fmt.Println("int", t)
	}
	t2, ok := a.(float32)
	if ok {
		fmt.Println("float32", t2)
	}
}

在进行安全的类型断言时,可以使用两个参数来接收返回值,其中第一个参数是转换成功后的值,一个是 bool,用于指示这次类型转换是否成功(如果转换失败,则 v 为期待转换类型的默认值),比如:

package main

import "fmt"

func main() {
	var s interface{} = "test"
	v1, ok := s.(int)
	if ok { // invalid type assertion: s.(string) (non-interface type string on left)
		fmt.Println(v1)
	}
	fmt.Println(v1)

	var s2 interface{} = 11
	v2, ok := s2.(AAA)
	if ok {
		fmt.Println(v2)
	}
	fmt.Println(v2)
}

type AAA struct {
	bb int
}

// output
0
{0}

强制类型转换

golang的类型转换和C/C++、Java等语言的类型转换还有点区别

  • C/C++等语言有隐式类型转换,Golang中没有
  • Golang中的类型转换分强制类型转换类型断言

在C/C++中:

int main()
{
    int a=5;
    float b=3.5;
    printf("%f",a*b);
}

这样的代码是没有问题的,编译器隐式的把a向上转为float类型。 但是在golang中,

package main

import "fmt"

func main() {
    var a float32 = 5.6
    var b int = 10
    fmt.Println (a * b)
}

这样的代码会报错,因为类型不匹配,这时候就需要强制类型转换:

package main

import "fmt"

func main() {
    var a float32 = 5.6
    var b int = 10
    fmt.Println (a * float32(b))
}

这样就不会报错了,普通变量类型int、float、string 都可以使用 type (a)这种形式来进行强制类型转换,,比如

var a int32  = 10
var b int64 = int64(a)
var c float32 = 12.3
var d float64 =float64(c)

String 与数值类型之间的转换

package main

import "strconv"

func main() {
	// string到int
	int, err := strconv.Atoi(string)
	// string到int64
	int64, err := strconv.ParseInt(string, 10, 64)
	// int到string
	string := strconv.Itoa(int)
	// int64到string
	string := strconv.FormatInt(int64, 10)
}

int32 枚举与数值类型之间的转换

package main

import "fmt"

type ConstantPromotionrulestatus int32

const (
	Constant_PROMOTION_RULE_STATUS_DISABLED ConstantPromotionrulestatus = 0
	Constant_PROMOTION_RULE_STATUS_DELETED  ConstantPromotionrulestatus = 1
)

func main() {
	var a int32 = int32(Constant_PROMOTION_RULE_STATUS_DISABLED)
	fmt.Println(a)

	var b int32 = 1
	var c ConstantPromotionrulestatus = ConstantPromotionrulestatus(b)
	fmt.Print(c)
}

指针的强制类型转换

golang中指针也是有类型的:

package main

func main() {
	var a int = 10
	var p *int = &a
	var c *int64
	c = (*int64)(p)
}

但是,上面代码会报编译错误,编译器会提示cannot convert p (type \*int) to type \*int64。因为,指针的强制类型转换需要用到unsafe包中的函数实现:

package main

import "unsafe"
import "fmt"

func main() {
	var a int = 10
	var b *int = &a
	var c *int64 = (*int64)(unsafe.Pointer(b))
	fmt.Println(*c)
}

Reference