Go 通过数组+;从值创建字符串

Go 通过数组+;从值创建字符串,go,Go,有了这段代码,是否有更好的方法循环遍历所有用户并创建一个包含所有用户Nick值的新字符串 package main import "fmt" type User struct { Nick string } func main() { var users [2]User users[0] = User{ Nick: "Radar" } users[1] = User{ Nick: "NotRadar" } names := ":"

有了这段代码,是否有更好的方法循环遍历所有用户并创建一个包含所有用户
Nick
值的新字符串

package main

import "fmt"

type User struct {
    Nick     string
}


func main() {
    var users [2]User
    users[0] = User{ Nick: "Radar" }
    users[1] = User{ Nick: "NotRadar" }
    names := ":"
    for _, u := range users {
        names += u.Nick + " "
    }
    fmt.Println(names)

}
比如说,

package main

import (
    "bytes"
    "fmt"
)

type User struct {
    Nick string
}

func main() {
    var users [2]User
    users[0] = User{Nick: "Radar"}
    users[1] = User{Nick: "NotRadar"}
    var buf bytes.Buffer
    buf.WriteByte(':')
    for _, u := range users {
        buf.WriteString(u.Nick)
        buf.WriteByte(' ')
    }
    names := buf.String()
    fmt.Println(names)
}
这避免了由于串接
string
s而导致的大量分配

你也可以写:

package main

import (
    "fmt"
)

type User struct {
    Nick string
}

func main() {
    var users [2]User
    users[0] = User{Nick: "Radar"}
    users[1] = User{Nick: "NotRadar"}
    var buf []byte
    buf = append(buf, ':')
    for _, u := range users {
        buf = append(buf, u.Nick...)
        buf = append(buf, ' ')
    }
    names := string(buf)
    fmt.Println(names)
}

看起来你真的想在这里吃点东西。您可能希望避免原始代码中重复字符串连接的紧密循环;我相当肯定Go没有为它的原始字符串实现数据结构

package main

import (
    "fmt"
    "strings"
)

type User struct {
    Nick string
}

func main() {
    var users [2]User
    users[0] = User{Nick: "Radar"}
    users[1] = User{Nick: "NotRadar"}
    userNames := []string{}
    for _, u := range users {
        userNames = append(userNames, u.Nick)
    }
    names := ":" + strings.Join(userNames, " ")
    fmt.Println(names)
}

不幸的是,我不知道有什么更优雅的方式来编写代码

Go确实有一个方法,因此如果您制作了一个帮助器,将您的用户数组转换为字符串片段(
[]string
),那么您可以将其传递到
string.Join


我认为Go的静态类型和缺少模板使得它很难像Ruby那样编写通用的
map
函数。有效地重写联接,以防止必须在列表上迭代额外的时间并分配额外的切片

func Usernames(users []User) string {
    if len(users) == 0 {
        return ""
    }
    if len(users) == 1 {
        return users[0].Name
    }

    sep := " "
    n := len(users)-1 // From len(sep) * len(a)-1, sep is always len 1 unlike in Join
    for i := 0; i < len(users); i++ {
        n += len(users[i].Name)
    }

    names := make([]byte,n)
    namesp := copy(names, users[0].Name)
    for _,u := range users[1:] {
        namesp += copy(names[namesp:], sep)
        namesp += copy(names[namesp:], u.Name)
    }
    return string(names)
}
func用户名(users[]User)字符串{
如果len(用户)==0{
返回“”
}
如果len(用户)==1{
返回用户[0]。名称
}
九月:=“”
n:=len(users)-1//From len(sep)*len(a)-1,sep与Join中的len 1不同
对于i:=0;i
作为参考,strings.go与strings一起。连接源:


请参见第356行

您对这种方法有什么问题?这对我来说似乎很标准(也许你想在某些情况下使用strings.TrimSpace(names)或names[:len(names)-1]来去掉多余的尾随空间)。好吧,我是一名Ruby程序员,在Ruby中我只需要做
users.map(&:name).join(“”)
。我想围棋中可能有一些明显的东西我错过了。啊,是的。我应该考虑一下。好主意:)使用字符串。连接在这里是多余的。如果您查看Join的源代码,它基本上是问题中示例代码的一个更奇特的变体,但它使用内置的copy()函数,而不是与“+=”串联。实际上,你只是在用strings.Join加倍你的工作。至少,如果要这样做,您应该将用户名:=[]字符串{}替换为用户名:=make([]字符串,0,len(用户)),否则“append”与“+=”处理字符串时遇到的问题相同。不,这实际上是不同的<代码>字符串。Join
对一个字符串进行单个分配,分配的字符串大小等于所有已连接字符串的组合大小(的第364-366行)。与重复分配越来越大的字符串相比,这种方法的效率要大得多。想想“高斯和”,你就会明白其中的根本原因。关于声明用户名容量的说明很好,但是append()在如何基于著名的动态数组扩展算法进行扩展方面更聪明。@Jsor:你能用你所说的代码来回答这个问题,以便我能理解吗?我应该补充一点,peterSO的回答也非常正确:它避免了重复串接的相同陷阱,而且比我的解决方案更灵活。我们最好合并这两个答案。我建议避免使用
字符串的内联。加入
,除非探查器告诉我们这对我们有很大帮助。没有测量或数据支持的优化可能会出错。不使用标准库意味着错过了对这些库未来的任何改进。