将自定义类型转换为基本类型

huangapple go评论72阅读模式
英文:

Type cast custom types to base types

问题

如何将自定义类型转换为interface{},然后再转换为基本类型(例如uint8)?

我不能像uint16(val.(Year))这样直接进行类型转换,因为我可能不知道所有的自定义类型,但我可以在运行时确定基本类型(uint8uint32等)。


有许多基于数字的自定义类型(通常用作枚举类型):

例如:

type Year  uint16
type Day   uint8
type Month uint8

等等...

问题是如何将interface{}类型转换为基本类型:

package main

import "fmt"

type Year uint16

// ....
//还有许多其他基于uint8的自定义类型

func AsUint16(val interface{}) uint16 {
    return val.(uint16) //FAIL: 无法将val(类型为interface{})转换为uint16类型:需要类型断言
}

func AsUint16_2(val interface{}) uint16 {
    return uint16(val) //FAIL: 无法将val(类型为interface{})转换为uint16类型:需要类型断言
}

func main() {
    fmt.Println(AsUint16_2(Year(2015)))
}

http://play.golang.org/p/cyAnzQ90At

英文:

How can I convert custom type to interface{} and then to base type (ex. uint8)?

I can't use direct cast like uint16(val.(Year)) because I may not know all custom types, but I can determinate base types (uint8, uint32,...) in runtime


There are many custom types (usually used as enums) based on numeric:

ex:

type Year  uint16
type Day   uint8
type Month uint8

and so on...

The question is about type casting from interface{} to base types:

package main

import "fmt"

type Year uint16

// ....
//Many others custom types based on uint8

func AsUint16(val interface{}) uint16 {
    return val.(uint16) //FAIL:  cannot convert val (type interface {}) to type uint16: need type assertion
}

func AsUint16_2(val interface{}) uint16 {
    return uint16(val) //FAIL:   cannot convert val (type interface {}) to type uint16: need type assertion
}

func main() {
	fmt.Println(AsUint16_2(Year(2015)))
}

http://play.golang.org/p/cyAnzQ90At

答案1

得分: 16

你可以使用reflect包来实现这个:

package main

import "fmt"
import "reflect"

type Year uint16

func AsUint16(val interface{}) uint16 {
    ref := reflect.ValueOf(val)
    if ref.Kind() != reflect.Uint16 {
        return 0
    }
    return uint16(ref.Uint())
}

func main() {
    fmt.Println(AsUint16(Year(2015)))
}

根据你的情况,你可能想要返回(uint16, error),而不是返回空值。

https://play.golang.org/p/sYm1jTCMIf

英文:

You can accomplish this by using the reflect package:

package main

import "fmt"
import "reflect"

type Year uint16

func AsUint16(val interface{}) uint16 {
	ref := reflect.ValueOf(val)
	if ref.Kind() != reflect.Uint16 {
		return 0
	}
	return uint16(ref.Uint())
}

func main() {
	fmt.Println(AsUint16(Year(2015)))
}

Depending on your situation, you may want to return (uint16, error), instead of returning the empty value.

https://play.golang.org/p/sYm1jTCMIf

答案2

得分: 9

你为什么在问题中包含了Year?你是希望将任意事物转换为年份,还是将年份转换为uint16?

如果我假设你指的是后一种情况,那么最好使用以下方法:

func (y Year) AsUint16() uint16 { 
    return uint16(y)
}

这个方法不需要进行任何类型断言或反射。

链接:https://play.golang.org/p/9wCQJe46PU

英文:

Why did you include Year in the question? Are you hoping to convert arbitrary things into Years, or convert Years into uint16s?

If I assume you meant the latter case, then it would be better to use a method

func (y Year) AsUint16() uint16 { 
    return uint16(y)
}

which doesn't need any type assertions or reflection.

https://play.golang.org/p/9wCQJe46PU

答案3

得分: 0

Go 1.18及以上版本

在引入泛型之后,现在更容易编写适用于任何定义类型的函数。

func AsUint16[T ~uint16](v T) uint16 {
     return uint16(v)
}

func AsUint8[T ~uint8](v T) uint8 {
     return uint8(v)
}

interface{}不同,这种转换是有效的,因为类型参数明确限制为具有特定底层类型的类型,使用波浪符号~(更多信息:https://stackoverflow.com/questions/70888240/whats-the-meaning-of-the-new-tilde-token-in-go)。

缺点是您必须为每个底层类型编写不同的函数,如上面的uint16uint8等。使用类型切换在函数体中可以使用联合约束,但在我看来,使用专门的函数更清晰 —— 结果是相同的。

英文:

Go 1.18 and above

After the introduction of generics, it's now easier to write such a function that works for any defined type.

func AsUint16[T ~uint16](v T) uint16 {
     return uint16(v)
}

func AsUint8[T ~uint8](v T) uint8 {
     return uint8(v)
}

Unlike with interface{}, the conversion works because the type parameter is explicitly constrained to types with that specific underlying type using tilde ~ (more info: https://stackoverflow.com/questions/70888240/whats-the-meaning-of-the-new-tilde-token-in-go).

The downside is that you must write a different function for each underlying type, as shown above with uint16, uint8, etc. A union constraint would work with a type switch in the function body, but in my opinion it's much clearer to use specialized functions — the result is the same.

huangapple
  • 本文由 发表于 2015年6月9日 04:35:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/30718602.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定