最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語(yǔ)言類(lèi)型轉(zhuǎn)換工具庫(kù)cast的實(shí)現(xiàn)

 更新時(shí)間:2025年11月21日 10:00:22   作者:PPPsych  
本文介紹了Go語(yǔ)言中的類(lèi)型轉(zhuǎn)換工具庫(kù)cast,cast庫(kù)提供了一種簡(jiǎn)單安全的方式來(lái)在各種類(lèi)型間轉(zhuǎn)換,如ToIntSliceE、ToStringSliceE等,同時(shí)支持時(shí)間類(lèi)型和時(shí)長(zhǎng)類(lèi)型的轉(zhuǎn)換,并能處理轉(zhuǎn)換失敗的情況,感興趣的可以了解一下

簡(jiǎn)介

cast可以在 Go 中輕松安全地從一種類(lèi)型轉(zhuǎn)換為另一種類(lèi)型,cast 提供了簡(jiǎn)單的函數(shù)來(lái)輕松地將數(shù)字轉(zhuǎn)換為字符串,將接口轉(zhuǎn)換為布爾值等。當(dāng)需要顯示類(lèi)型轉(zhuǎn)換時(shí),cast 會(huì)智能地執(zhí)行轉(zhuǎn)換操作。

快速入門(mén)

安裝

go get github.com/spf13/cast

使用

package main

import (
	"fmt"

	"github.com/spf13/cast"
)

func main() {
	// ToString
	fmt.Println(cast.ToString("leedarjun"))        // leedarjun
	fmt.Println(cast.ToString(8))                  // 8
	fmt.Println(cast.ToString(8.31))               // 8.31
	fmt.Println(cast.ToString([]byte("one time"))) // one time
	fmt.Println(cast.ToString(nil))                // ""

	var foo interface{} = "one more time"
	fmt.Println(cast.ToString(foo)) // one more time

	// ToInt
	fmt.Println(cast.ToInt(8))     // 8
	fmt.Println(cast.ToInt(8.31))  // 8
	fmt.Println(cast.ToInt("8"))   // 8
	fmt.Println(cast.ToInt(true))  // 1
	fmt.Println(cast.ToInt(false)) // 0

	var eight interface{} = 8
	fmt.Println(cast.ToInt(eight)) // 8
	fmt.Println(cast.ToInt(nil))   // 0
}

實(shí)際上,cast實(shí)現(xiàn)了多種常見(jiàn)類(lèi)型之間的相互轉(zhuǎn)換,返回最符合直覺(jué)的結(jié)果。例如:

  • nil轉(zhuǎn)為string的結(jié)果為"",而不是"nil"
  • true轉(zhuǎn)為string的結(jié)果為"true",而true轉(zhuǎn)為int的結(jié)果為1;
  • interface{}轉(zhuǎn)為其他類(lèi)型,要看它里面存儲(chǔ)的值類(lèi)型。

這些類(lèi)型包括所有的基本類(lèi)型(整形、浮點(diǎn)型、布爾值和字符串)、空接口、nil,時(shí)間(time.Time)、時(shí)長(zhǎng)(time.Duration)以及它們的切片類(lèi)型,還有map[string]Type(其中Type為前面提到的類(lèi)型):

byte     bool      float32    float64    string  
int8     int16     int32      int64      int
uint8    uint16    uint32     uint64     uint
interface{}   time.Time  time.Duration   nil

高級(jí)轉(zhuǎn)換

cast提供了兩組函數(shù):

  • ToType(其中Type可以為任何支持的類(lèi)型),將參數(shù)轉(zhuǎn)換為Type類(lèi)型。如果無(wú)法轉(zhuǎn)換,返回Type類(lèi)型的零值或nil;
  • ToTypeE以 E 結(jié)尾,返回轉(zhuǎn)換后的值和一個(gè)error。這組函數(shù)可以區(qū)分參數(shù)中實(shí)際存儲(chǔ)了零值,還是轉(zhuǎn)換失敗了。

實(shí)現(xiàn)上大部分代碼都類(lèi)似,ToType在內(nèi)部調(diào)用ToTypeE函數(shù),返回結(jié)果并忽略錯(cuò)誤。ToType函數(shù)的實(shí)現(xiàn)在文件cast.go中,而ToTypeE函數(shù)的實(shí)現(xiàn)在文件caste.go中。

部分源碼如下:

// ToBoolE casts an interface to a bool type. 
func ToBool(i interface{}) bool {
  v, _ := ToBoolE(i)
  return v
}

// ToDuration casts an interface to a time.Duration type.
func ToDuration(i interface{}) time.Duration {
  v, _ := ToDurationE(i)
  return v
}

ToTypeE函數(shù)都接受任意類(lèi)型的參數(shù)(interface{}),然后使用類(lèi)型斷言根據(jù)具體的類(lèi)型來(lái)執(zhí)行不同的轉(zhuǎn)換。如果無(wú)法轉(zhuǎn)換,返回錯(cuò)誤。

// ToBoolE casts an interface to a bool type.
func ToBoolE(i interface{}) (bool, error) {
	i = indirect(i)

	switch b := i.(type) {
	case bool:
		return b, nil
	case nil:
		return false, nil
	case int:
		if i.(int) != 0 {
			return true, nil
		}
		return false, nil
	case string:
		return strconv.ParseBool(i.(string))
	case json.Number:
		v, err := ToInt64E(b)
		if err == nil {
			return v != 0, nil
		}
		return false, fmt.Errorf("unable to cast %#v of type %T to bool", i, i)
	default:
		return false, fmt.Errorf("unable to cast %#v of type %T to bool", i, i)
	}
}

首先調(diào)用indirect函數(shù)將參數(shù)中可能的指針去掉。如果類(lèi)型本身不是指針,那么直接返回。否則返回指針指向的值。循環(huán)直到返回一個(gè)非指針的值:

// From html/template/content.go
// Copyright 2011 The Go Authors. All rights reserved.
// indirect returns the value, after dereferencing as many times
// as necessary to reach the base type (or nil).
func indirect(a interface{}) interface{} {
	if a == nil {
		return nil
	}
	if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
		// Avoid creating a reflect.Value if it's not a pointer.
		return a
	}
	v := reflect.ValueOf(a)
	for v.Kind() == reflect.Ptr && !v.IsNil() {
		v = v.Elem()
	}
	return v.Interface()
}

所以,下面代碼輸出都是 8:

package main

import (
    "fmt"

    "github.com/spf13/cast"
)

func main() {
  p := new(int)
  *p = 8
  fmt.Println(cast.ToInt(p))   // 8

  pp := &p
  fmt.Println(cast.ToInt(pp))  // 8
}

時(shí)間和時(shí)長(zhǎng)轉(zhuǎn)換

時(shí)間類(lèi)型的轉(zhuǎn)換

源碼如下:

// ToTimeE casts an interface to a time.Time type.
func ToTimeE(i interface{}) (tim time.Time, err error) {
	return ToTimeInDefaultLocationE(i, time.UTC)
}

// ToTimeInDefaultLocationE casts an empty interface to time.Time,
// interpreting inputs without a timezone to be in the given location,
// or the local timezone if nil.
func ToTimeInDefaultLocationE(i interface{}, location *time.Location) (tim time.Time, err error) {
	i = indirect(i)

	switch v := i.(type) {
	case time.Time:
		return v, nil
	case string:
		return StringToDateInDefaultLocation(v, location)
	case json.Number:
		s, err1 := ToInt64E(v)
		if err1 != nil {
			return time.Time{}, fmt.Errorf("unable to cast %#v of type %T to Time", i, i)
		}
		return time.Unix(s, 0), nil
	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)
	}
}

根據(jù)傳入的類(lèi)型執(zhí)行不同的處理:

  • 如果是time.Time,直接返回;
  • 如果是整型,將參數(shù)作為時(shí)間戳(自 UTC 時(shí)間1970.01.01 00:00:00到現(xiàn)在的秒數(shù))調(diào)用time.Unix生成時(shí)間。Unix接受兩個(gè)參數(shù),第一個(gè)參數(shù)指定秒,第二個(gè)參數(shù)指定納秒;
  • 如果是字符串,調(diào)用StringToDate函數(shù)依次嘗試以下面這些時(shí)間格式調(diào)用time.Parse解析該字符串。如果某個(gè)格式解析成功,則返回獲得的time.Time。否則解析失敗,返回錯(cuò)誤;
  • 其他任何類(lèi)型都無(wú)法轉(zhuǎn)換為time.Time

字符串轉(zhuǎn)換為時(shí)間

源碼:

// cast/caste.go
func StringToDate(s string) (time.Time, error) {
  return parseDateWith(s, []string{
    time.RFC3339,
    "2006-01-02T15:04:05", // iso8601 without timezone
    time.RFC1123Z,
    time.RFC1123,
    time.RFC822Z,
    time.RFC822,
    time.RFC850,
    time.ANSIC,
    time.UnixDate,
    time.RubyDate,
    "2006-01-02 15:04:05.999999999 -0700 MST", // Time.String()
    "2006-01-02",
    "02 Jan 2006",
    "2006-01-02T15:04:05-0700", // RFC3339 without timezone hh:mm colon
    "2006-01-02 15:04:05 -07:00",
    "2006-01-02 15:04:05 -0700",
    "2006-01-02 15:04:05Z07:00", // RFC3339 without T
    "2006-01-02 15:04:05Z0700",  // RFC3339 without T or timezone hh:mm colon
    "2006-01-02 15:04:05",
    time.Kitchen,
    time.Stamp,
    time.StampMilli,
    time.StampMicro,
    time.StampNano,
  })
}

func parseDateWith(s string, dates []string) (d time.Time, e error) {
  for _, dateType := range dates {
    if d, e = time.Parse(dateType, s); e == nil {
      return
    }
  }
  return d, fmt.Errorf("unable to parse date: %s", s)
}

時(shí)長(zhǎng)類(lèi)型的轉(zhuǎn)換

源碼如下:

// cast/caste.go
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
  }
}

根據(jù)傳入的類(lèi)型進(jìn)行不同的處理:

  • 如果是time.Duration類(lèi)型,直接返回;
  • 如果是整型或浮點(diǎn)型,將其數(shù)值強(qiáng)制轉(zhuǎn)換為time.Duration類(lèi)型,單位默認(rèn)為ns;
  • 如果是字符串,分為兩種情況:如果字符串中有時(shí)間單位符號(hào)nsuµmh,直接調(diào)用time.ParseDuration解析;否則在字符串后拼接ns再調(diào)用time.ParseDuration解析;
  • 其他類(lèi)型解析失敗。

示例:

package main

import (
  "fmt"
  "time"

  "github.com/spf13/cast"
)

func main() {
  now := time.Now()
  timestamp := 1579615973
  timeStr := "2020-01-21 22:13:48"

  fmt.Println(cast.ToTime(now))       // 2020-01-22 06:31:50.5068465  0800 CST m= 0.000997701
  fmt.Println(cast.ToTime(timestamp)) // 2020-01-21 22:12:53  0800 CST
  fmt.Println(cast.ToTime(timeStr))   // 2020-01-21 22:13:48  0000 UTC

  d, _ := time.ParseDuration("1m30s")
  ns := 30000
  strWithUnit := "130s"
  strWithoutUnit := "130"

  fmt.Println(cast.ToDuration(d))               // 1m30s
  fmt.Println(cast.ToDuration(ns))              // 30μs
  fmt.Println(cast.ToDuration(strWithUnit))     // 2m10s
  fmt.Println(cast.ToDuration(strWithoutUnit))  // 130ns
}

轉(zhuǎn)換為切片

實(shí)際上,這些函數(shù)的實(shí)現(xiàn)基本類(lèi)似。使用類(lèi)型斷言判斷類(lèi)型。如果就是要返回的類(lèi)型,直接返回。否則根據(jù)類(lèi)型進(jìn)行相應(yīng)的轉(zhuǎn)換。

我們主要分析兩個(gè)實(shí)現(xiàn):ToIntSliceEToStringSliceE。ToBoolSliceE/ToDurationSliceEToIntSliceE基本相同。

ToIntSliceE

源碼如下:

func ToIntSliceE(i interface{}) ([]int, error) {
  if i == nil {
    return []int{}, fmt.Errorf("unable to cast %#v of type %T to []int", i, i)
  }

  switch v := i.(type) {
  case []int:
    return v, nil
  }

  kind := reflect.TypeOf(i).Kind()
  switch kind {
  case reflect.Slice, reflect.Array:
    s := reflect.ValueOf(i)
    a := make([]int, s.Len())
    for j := 0; j < s.Len(); j   {
      val, err := ToIntE(s.Index(j).Interface())
      if err != nil {
        return []int{}, fmt.Errorf("unable to cast %#v of type %T to []int", i, i)
      }
      a[j] = val
    }
    return a, nil
  default:
    return []int{}, fmt.Errorf("unable to cast %#v of type %T to []int", i, i)
  }
}

根據(jù)傳入?yún)?shù)的類(lèi)型:

  • 如果是nil,直接返回錯(cuò)誤;
  • 如果是[]int,不用轉(zhuǎn)換,直接返回;
  • 如果傳入類(lèi)型為切片數(shù)組,新建一個(gè)[]int,將切片或數(shù)組中的每個(gè)元素轉(zhuǎn)為int放到該[]int中。最后返回這個(gè)[]int;
  • 其他情況,不能轉(zhuǎn)換。

ToStringSliceE

源碼如下:

func ToStringSliceE(i interface{}) ([]string, error) {
  var a []string

  switch v := i.(type) {
  case []interface{}:
    for _, u := range v {
      a = append(a, ToString(u))
    }
    return a, nil
  case []string:
    return v, nil
  case string:
    return strings.Fields(v), nil
  case interface{}:
    str, err := ToStringE(v)
    if err != nil {
      return a, fmt.Errorf("unable to cast %#v of type %T to []string", i, i)
    }
    return []string{str}, nil
  default:
    return a, fmt.Errorf("unable to cast %#v of type %T to []string", i, i)
  }
}

根據(jù)傳入的參數(shù)類(lèi)型:

  • 如果是[]interface{},將該參數(shù)中每個(gè)元素轉(zhuǎn)為string,返回結(jié)果切片;
  • 如果是[]string,不需要轉(zhuǎn)換,直接返回;
  • 如果是interface{},將參數(shù)轉(zhuǎn)為string,返回只包含這個(gè)值的切片;
  • 如果是string,調(diào)用strings.Fields函數(shù)按空白符將參數(shù)拆分,返回拆分后的字符串切片;
  • 其他情況,不能轉(zhuǎn)換。

示例:

package main

import (
  "fmt"

  "github.com/spf13/cast"
)

func main() {
  sliceOfInt := []int{1, 3, 7}
  arrayOfInt := [3]int{8, 12}
  // ToIntSlice
  fmt.Println(cast.ToIntSlice(sliceOfInt))  // [1 3 7]
  fmt.Println(cast.ToIntSlice(arrayOfInt))  // [8 12 0]

  sliceOfInterface := []interface{}{1, 2.0, "darjun"}
  sliceOfString := []string{"abc", "dj", "pipi"}
  stringFields := " abc  def hij   "
  any := interface{}(37)
  // ToStringSliceE
  fmt.Println(cast.ToStringSlice(sliceOfInterface))  // [1 2 darjun]
  fmt.Println(cast.ToStringSlice(sliceOfString))     // [abc dj pipi]
  fmt.Println(cast.ToStringSlice(stringFields))      // [abc def hij]
  fmt.Println(cast.ToStringSlice(any))               // [37]
}

轉(zhuǎn)為map[string]Type類(lèi)型

cast庫(kù)能將傳入的參數(shù)轉(zhuǎn)為map[string]Type類(lèi)型,Type為上面支持的類(lèi)型。

其實(shí)只需要分析一個(gè)ToStringMapStringE函數(shù)就可以了,其他的實(shí)現(xiàn)基本一樣。ToStringMapStringE返回map[string]string類(lèi)型的值。

源碼如下:

func ToStringMapStringE(i interface{}) (map[string]string, error) {
  var m = map[string]string{}

  switch v := i.(type) {
  case map[string]string:
    return v, nil
  case map[string]interface{}:
    for k, val := range v {
      m[ToString(k)] = ToString(val)
    }
    return m, nil
  case map[interface{}]string:
    for k, val := range v {
      m[ToString(k)] = ToString(val)
    }
    return m, nil
  case map[interface{}]interface{}:
    for k, val := range v {
      m[ToString(k)] = ToString(val)
    }
    return m, nil
  case string:
    err := jsonStringToObject(v, &m)
    return m, err
  default:
    return m, fmt.Errorf("unable to cast %#v of type %T to map[string]string", i, i)
  }
}

根據(jù)傳入的參數(shù)類(lèi)型:

  • 如果是map[string]string,不用轉(zhuǎn)換,直接返回;
  • 如果是map[string]interface{},將每個(gè)值轉(zhuǎn)為string存入新的 map,最后返回新的 map;
  • 如果是map[interface{}]string,將每個(gè)鍵轉(zhuǎn)為string存入新的 map,最后返回新的 map;
  • 如果是map[interface{}]interface{},將每個(gè)鍵和值都轉(zhuǎn)為string存入新的 map,最后返回新的 map;
  • 如果是string類(lèi)型,cast將它看成一個(gè) JSON 串,解析這個(gè) JSON 到map[string]string,然后返回結(jié)果;
  • 其他情況,返回錯(cuò)誤。

示例:

package main

import (
  "fmt"

  "github.com/spf13/cast"
)

func main() {
  m1 := map[string]string {
    "name": "darjun",
    "job": "developer",
  }

  m2 := map[string]interface{} {
    "name": "jingwen",
    "age": 18,
  }

  m3 := map[interface{}]string {
    "name": "pipi",
    "job": "designer",
  }

  m4 := map[interface{}]interface{} {
    "name": "did",
    "age": 29,
  }

  jsonStr := `{"name":"bibi", "job":"manager"}`

  fmt.Println(cast.ToStringMapString(m1))      // map[job:developer name:darjun]
  fmt.Println(cast.ToStringMapString(m2))      // map[age:18 name:jingwen] 
  fmt.Println(cast.ToStringMapString(m3))      // map[job:designer name:pipi]
  fmt.Println(cast.ToStringMapString(m4))      // map[job:designer name:pipi]
  fmt.Println(cast.ToStringMapString(jsonStr)) // map[job:manager name:bibi]
}

到此這篇關(guān)于Go語(yǔ)言類(lèi)型轉(zhuǎn)換工具庫(kù)cast的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Go語(yǔ)言類(lèi)型轉(zhuǎn)換工具庫(kù)cast內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Gin框架使用Zap接收日志的實(shí)現(xiàn)

    Gin框架使用Zap接收日志的實(shí)現(xiàn)

    在Gin框架中使用Zap日志中間件替代默認(rèn)日志,通過(guò)封裝日志包提升性能,實(shí)現(xiàn)更高效的日志記錄與異?;謴?fù)功能,下面就來(lái)介紹一下Gin框架使用Zap接收日志的實(shí)現(xiàn),感興趣的可以了解一下
    2025-05-05
  • Go語(yǔ)言基礎(chǔ)數(shù)組用法及示例詳解

    Go語(yǔ)言基礎(chǔ)數(shù)組用法及示例詳解

    這篇文章主要為大家介紹了Go語(yǔ)言基礎(chǔ)Go語(yǔ)言數(shù)組的用法及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2021-11-11
  • Go語(yǔ)言中更優(yōu)雅的錯(cuò)誤處理

    Go語(yǔ)言中更優(yōu)雅的錯(cuò)誤處理

    Go語(yǔ)言中的錯(cuò)誤處理是一個(gè)被大家經(jīng)常拿出來(lái)討論的話題(另外一個(gè)是泛型)。篇文章我們將討論一下如何在現(xiàn)行的 Golang 框架下提供更友好和優(yōu)雅的錯(cuò)誤處理。需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。
    2017-02-02
  • 最新評(píng)論

    乐安县| 樟树市| 仪陇县| 津市市| 嫩江县| 济阳县| 涟水县| 聊城市| 翼城县| 特克斯县| 沙田区| 桂东县| 延庆县| 汝南县| 雷波县| 江华| 肥城市| 察雅县| 桃园市| 怀宁县| 武汉市| 宜宾市| 西充县| 陆良县| 镇坪县| 年辖:市辖区| 博野县| 四子王旗| 石家庄市| 北安市| 长白| 兴海县| 平泉县| 临城县| 固原市| 高陵县| 湘潭市| 潜江市| 天祝| 新河县| 绿春县|