试试这样进行Go类型转换

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情

go语言的基本数据类型很丰富,光是整数类型就有int8,int16,int32,int64,uint64,这些类型在工作中非常常见,go的interface{}可以接收任意值,所以有些时候在进行类型之间转换,也会变得非常的麻烦,比如,将一个interface{}转换成int类型,因为我们不知道interface{}中具体是什么类型,我们只能通过下面的方式进行类型转换


func Convert2Int(v interface{}) (int,error) {
	switch s := v.(type) {
	case int64:
		return int(s), nil
	case int32:
		return int(s), nil
	case int16:
		return int(s), nil
	case int8:
		return int(s), nil
	case uint:
		return int(s), nil
	case uint64:
		return int(s), nil
	case uint32:
		return int(s), nil
	case uint16:
		return int(s), nil
	case uint8:
		return int(s), nil
	case float64:
		return int(s), nil
	case float32:
		return int(s), nil
	default:
		return 0, fmt.Errorf("unable to cast %#v of type %T to int", v, v)
	}

}

因为他可能是任意类型,所以我们只能一个类型一个类型的去判断,这使得我们的业务代码变得非常的臃肿。而且写这么多的case很有可能一不留神就少些一个,为我们的程序埋下bug

下面来看看开源库cast是怎么解决这个头疼的问题的

Go Cast

安装cast

go get github.com/spf13/cast

cast提供了interface{}类型向任意基本类型的转换API,

image.png

我们只需要调用他的api,一行代码就可以搞定interface向任意类型转换

实现原理

来看看他是怎么实现的吧,以ToInt为例

func ToInt(i interface{}) int {
	v, _ := ToIntE(i)
	return v
}
func ToIntE(i interface{}) (int, error) {
        // 如果是指针类型,那么取出具体对应的值
	i = indirect(i)

	intv, ok := toInt(i)
	if ok {
		return intv, nil
	}

	switch s := i.(type) {
	case int64:
		return int(s), nil
	case int32:
		return int(s), nil
	case int16:
		return int(s), nil
	case int8:
		return int(s), nil
	case uint:
		return int(s), nil
	case uint64:
		return int(s), nil
	case uint32:
		return int(s), nil
	case uint16:
		return int(s), nil
	case uint8:
		return int(s), nil
	case float64:
		return int(s), nil
	case float32:
		return int(s), nil
	case string:
		v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
		if err == nil {
			return int(v), nil
		}
		return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i)
	case json.Number:
		return ToIntE(string(s))
	case bool:
		if s {
			return 1, nil
		}
		return 0, nil
	case nil:
		return 0, nil
	default:
		return 0, fmt.Errorf("unable to cast %#v of type %T to int", i, i)
	}
}

可以看出cast也是通过一个一个case进行类型转换的

但是他的case要比我们写的要全面的多,

比如bool类型,会很贴心的转换成01

string类型会帮助我们自动通过strconv转换成基本数据类型。

Cast进阶

cast除了帮我们做了基本数据类型的转换,还帮助我们做了日期相关的转换

interface{}转Duration

func ToDuration(i interface{}) time.Duration {
  v, _ := ToDurationE(i)
  return v
}
func ToDurationE(i interface{}) (d time.Duration, err error) {
  i = indirect(i)

  switch s := i.(type) {
  case time.Duration:
    return s, nil
  case int, int64, int32, int16, int8, uint, uint64, uint32, uint16, uint8:
    d = time.Duration(ToInt64(s))
    return
  case float32, float64:
    d = time.Duration(ToFloat64(s))
    return
  case string:
    if strings.ContainsAny(s, "nsuµmh") {
      d, err = time.ParseDuration(s)
    } else {
      d, err = time.ParseDuration(s + "ns")
    }
    return
  default:
    err = fmt.Errorf("unable to cast %#v of type %T to Duration", i, i)
    return
  }
}

根据传入的类型进行不同的处理:

  • 如果是time.Duration类型,直接返回;

  • 如果是整型或浮点型,将其数值强制转换为time.Duration类型,单位默认为ns

  • 如果是字符串,分为两种情况:如果字符串中有时间单位符号nsuµmh,直接调用time.ParseDuration解析;否则在字符串后拼接ns再调用time.ParseDuration解析;

  • 其他类型解析失败。

时间类型转换

func ToTimeE(i interface{}) (tim time.Time, err error) {
  i = indirect(i)

  switch v := i.(type) {
  case time.Time:
    return v, nil
  case string:
    return StringToDate(v)
  case int:
    return time.Unix(int64(v), 0), nil
  case int64:
    return time.Unix(v, 0), nil
  case int32:
    return time.Unix(int64(v), 0), nil
  case uint:
    return time.Unix(int64(v), 0), nil
  case uint64:
    return time.Unix(int64(v), 0), nil
  case uint32:
    return time.Unix(int64(v), 0), nil
  default:
    return time.Time{}, fmt.Errorf("unable to cast %#v of type %T to Time", i, i)
  }
}

根据传入的类型执行不同的处理:

  • 如果是time.Time,直接返回;

  • 如果是整型,将参数作为时间戳(自 UTC 时间1970.01.01 00:00:00到现在的秒数)调用time.Unix生成时间。Unix接受两个参数,第一个参数指定秒,第二个参数指定纳秒;

  • 如果是字符串,调用StringToDate函数依次尝试以下面这些时间格式调用time.Parse解析该字符串。如果某个格式解析成功,则返回获得的time.Time。否则解析失败,返回错误;

  • 其他任何类型都无法转换为time.Time

切片和map类型转换

转换为切片

image.png

转换为map[string]type

image.png

猜你喜欢

转载自juejin.im/post/7111704496698458119