Golang 将切片连接成字符串

在这里插入图片描述

1.问题

大咖好呀,我是恋喵大鲤鱼。

如何将一个切片连接成一个字符串呢?

您最先想到的可能是标准库 strings 包的 Join 函数。

func Join(elems []string, sep string) string

Join 将字符串切片的所有元素连接成一个字符串,各个元素间使用给定的字符串分隔。

package main

import (
	"fmt"
	"strings"
)

func main() {
	s := []string{"foo", "bar", "baz"}
	fmt.Println(strings.Join(s, ", "))
}

运行输出:

foo, bar, baz

strings.Join 只能将字符串切片连接成字符串,但对于其他类型的切片呢?

事实上,标准库并没有针对每种类型的切片都给出一个实现,也没有使用反射给出一个通用的实现。既然没有那我们自己来实现一个吧。

2.使用反射实现

如果想要将任意类型的切片连接成字符串,可以使用反射(reflect)包来动态处理不同类型的切片,将元素转换为字符串,并连接成一个字符串。

// JoinE concatenates all elements of Array, Slice or String to a single string with a separator
// and returns an error if an error occurred.
// E.g. input []int{1, 2, 3} and separator ",", output is a string "1,2,3".
// It panics if a's Kind is not Array, Slice, or String.
func JoinE(a any, sep string) (string, error) {
	v := reflect.ValueOf(a)
	if v.Kind() == reflect.String {
		return JoinE(strings.Split(a.(string), ""), sep)
	}
	var s string
	for i := 0; i < v.Len(); i++ {
		if len(s) > 0 {
			s += sep
		}
		str, err := conv.ToStringE(v.Index(i).Interface())
		if err != nil {
			return "", err
		}
		s += str
	}
	return s, nil
}

其中 ToStringE 是将任意类型转为字符串。

// ToStringE casts any type to a string type.
func ToStringE(i any) (string, error) {
	i = indirectToStringerOrError(i)

	switch s := i.(type) {
	case string:
		return s, nil
	case bool:
		return strconv.FormatBool(s), nil
	case int:
		return strconv.Itoa(s), nil
	case int64:
		return strconv.FormatInt(s, 10), nil
	case int32:
		return strconv.Itoa(int(s)), nil
	case int16:
		return strconv.FormatInt(int64(s), 10), nil
	case int8:
		return strconv.FormatInt(int64(s), 10), nil
	case uint:
		return strconv.FormatUint(uint64(s), 10), nil
	case uint64:
		return strconv.FormatUint(uint64(s), 10), nil
	case uint32:
		return strconv.FormatUint(uint64(s), 10), nil
	case uint16:
		return strconv.FormatUint(uint64(s), 10), nil
	case uint8:
		return strconv.FormatUint(uint64(s), 10), nil
	case float64:
		return strconv.FormatFloat(s, 'f', -1, 64), nil
	case float32:
		return strconv.FormatFloat(float64(s), 'f', -1, 32), nil
	case json.Number:
		return s.String(), nil
	case []byte:
		return string(s), nil
	case template.HTML:
		return string(s), nil
	case template.HTMLAttr:
		return string(s), nil
	case template.URL:
		return string(s), nil
	case template.JS:
		return string(s), nil
	case template.JSStr:
		return string(s), nil
	case template.CSS:
		return string(s), nil
	case template.Srcset:
		return string(s), nil
	case nil:
		return "", nil
	case fmt.Stringer:
		return s.String(), nil
	case error:
		return s.Error(), nil
	default:
		return "", fmt.Errorf("unable to cast %#v of type %T to string", i, i)
	}
}

// Copied from html/template/content.go.
// indirectToStringerOrError returns the value, after dereferencing as many times
// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
// or error.
func indirectToStringerOrError(a any) any {
	if a == nil {
		return nil
	}
	v := reflect.ValueOf(a)
	for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Pointer && !v.IsNil() {
		v = v.Elem()
	}
	return v.Interface()
}

如果不关心错误,可以再封装一下。

// Join concatenates all elements of Array, Slice or String to a single string with a separator.
func Join(a any, sep string) string {
	s, _ := JoinE(a, sep)
	return s
}

我们使用不同类型的切片来验证一下。

package main

import (
	"fmt"
	"strings"
)

func main() {
	s := []string{"foo", "bar", "baz"}
	fmt.Println(Join(s, ", "))
	
	i := []int{1, 2, 3}
	fmt.Println(Join(i, ", "))

	f := []float64{1.1, 2.2, 3.3}
	fmt.Println(Join(f, ", "))
	
	b := []bool{true, false, true}
	fmt.Println(Join(b, ", "))

	// 可以将字符串看成字符切片。
	str := "foo"
	fmt.Println(Join(str, ", "))
}

运行输出:

foo, bar, baz
1, 2, 3
1.1, 2.2, 3.3
true, false, true
f, o, o

输出符合预期,我们通过反射,只用一个函数便可将任意类型的切片连接成字符串。

3.dablelv/cyan

以上代码已放到开源 Go 工具函数库 dablelv/cyan,可直接通过 go mod 方式进行 import 然后使用。

欢迎大家协同共建该工具函数库。

import (
	"github.com/dablelv/cyan/str"
)

str.Join([]string{"foo", "bar", "baz"}, ", ")
str.Join([]int{1, 2, 3}, ", ")
str.Join([]float64{1.1, 2.2, 3.3}, ", ")
str.Join([]bool{true, false, true}, ", ")
str.Join("foo", ", ")

4.小结

对于字符串切片可以使用标准库 strings.Join 函数,对于其他任意类型的切片,利用 Golang 提供的反射能力,在运行时将切片元素转换为字符串并连接到一起。

如果您喜欢这篇文章,欢迎关注我的微信公众号“恋喵大鲤鱼”了解最新精彩内容。


参考文献

strings - Go Packages
github.com/dablelv/go-huge-util

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值