Golang:在字符串的类型别名上使用string.join

y1aodyip  于 2023-10-14  发布在  Go
关注(0)|答案(4)|浏览(119)

我有一个字符串的类型别名,
类型SpecialScopes字符串
我想用字符串连接一个这种类型的数组。

func MergeScopes(scopes ...SpecialScopes) SpecialScopes {
    return strings.Join(scopes, ",")
}

但与上述我得到的错误

cannot use scopes (type []SpecialScopes) as type []string in argument to strings.Join
cannot use strings.Join(scopes, ",") (type string) as type SpecialScopes in return argument

有没有一种方法可以让golang意识到SpecialScopes只是字符串的另一个名称,并在其上执行join函数?如果没有,那么最有效的方法是什么?我看到的一种方法是将数组中的所有元素强制转换为string,join,然后将其强制转换回SpecialScopes并返回值
更新1:我有一个可以转换值的工作实现。有没有更快的方法来做到这一点的建议?

func MergeScopes(scopes ...SpecialScopes) SpecialScopes {
    var s []string
    for _, scope := range scopes {
        s = append(s, string(scope))
    }

    return SpecialScopes(strings.Join(s, ","))
}
brccelvz

brccelvz1#

这是最快的方法,而不使用不安全的。

func MergeScopes(scopes ...SpecialScopes) SpecialScopes {
    if len(scopes) == 0 {
        return ""
    }
    var (
        sep = []byte(", ")
        // preallocate for len(sep) + assume at least 1 character
        out = make([]byte, 0, (1+len(sep))*len(scopes))
    )
    for _, s := range scopes {
        out = append(out, s...)
        out = append(out, sep...)
    }
    return SpecialScopes(out[:len(out)-len(sep)])
}

基准代码:https://play.golang.org/p/DrB8nM-6ws

━➤ go test -benchmem -bench=.  -v -benchtime=2s
testing: warning: no tests to run
BenchmarkUnsafe-8       30000000               109 ns/op              32 B/op          2 allocs/op
BenchmarkBuffer-8       20000000               255 ns/op             128 B/op          2 allocs/op
BenchmarkCopy-8         10000000               233 ns/op             112 B/op          3 allocs/op
BenchmarkConcat-8       30000000               112 ns/op              32 B/op          2 allocs/op
slwdgvem

slwdgvem2#

下面是一个使用unsafe包的解决方案:

func MergeScopes(scopes ...SpecialScopes) SpecialScopes {
    specialScopes := *(*[]string)((unsafe.Pointer(&scopes)))
    s := strings.Join(specialScopes, ",")
    return *(*SpecialScopes)((unsafe.Pointer(&s)))
}

https://play.golang.org/p/-wsHY2eCdc

hec6srdp

hec6srdp3#

如果你真的想要快速的东西,这是Go中更快的方法:

func MergeScopes(scopes ...SpecialScopes) SpecialScopes {
    var buffer bytes.Buffer
    for ix, s := range scopes {
        buffer.WriteString(string(s))
        if ix < len(scopes)-1 {
            buffer.WriteString(", ")    
        }
    }

    return SpecialScopes(buffer.String())
}

完整示例:https://play.golang.org/p/McWjh1yxHf
我知道它看起来不像一个简单的.Join(),但它很容易阅读。

qfe3c7zg

qfe3c7zg4#

如果你有多个类型别名,并且发现自己重复了相同的代码,你可以使用下面的 (如果你使用的是go 1.18或更高版本)

package strings

import "fmt"

type String interface {
    ~string
}

func Join[s String](str []s, sep s) s {
    if len(str) == 0 {
        return ""
    }

    if len(str) == 1 {
        return str[0]
    }

    joined := str[0]
    for _, s := range str[1:] {
        joined += sep + s
    }

    return joined
}

该函数可以像这样调用

strings.Join(scopes, ",")

相关问题