遍历数组的更干净方法+从值创建字符串

With this code, is there a better way to loop through all the users and create a new string containing all their Nick values?

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)

}

It really looks like you want a strings.Join here. You probably want to avoid that tight loop of repeated string concatenations in the original code; I'm fairly certain that Go doesn't implement a rope-like data structure for its primitive strings.

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)
}

For example,

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)
}

This avoids a lot of allocations due to the concatenation of strings.

You could also write:

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)
}

Unfortunately, I do not know of a more elegant way to write that code.

Go does have a String.Join method so if you made a helper that converted your array of users to a slice of strings ([]string) then you could pass that to String.Join.

I think that Go's static typing and lack of templates makes it hard to write a general purpose map function like Ruby has.

This is what I was talking about in the comments of dyoo's post. Effectively a rewrite of join to prevent having to iterate over the list an extra time and allocate an extra slice.

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)
}

For reference, strings.go with the strings.Join source: http://golang.org/src/pkg/strings/strings.go

See line 356