A string is a sequence of characters, but in memory it is a sequence of bytes read through an encoding (UTF-8, UTF-16). That explains most surprises with text.
Immutable
In Go and in Java, strings are immutable: “changing” a string creates another one. That makes them safe to share between threads and to use as map keys.
The length depends on what you count
| Language | Representation | "é" | "😀" |
|---|---|---|---|
| Go | UTF-8 bytes | len("é") = 2 bytes | len("😀") = 4 bytes |
| Java | UTF-16 units | "é".length() = 1 | "😀".length() = 2 |
To count characters the way a person would:
utf8.RuneCountInString("olá") // 3 (len("olá") is 4)for i, r := range "olá" { // range walks runes, not bytes fmt.Println(i, string(r))}"😀".codePointCount(0, "😀".length()); // 1Concatenating in a loop
Since each concatenation creates a new string, joining thousands of pieces with + copies everything again on every iteration. Use a builder:
var b strings.Builderfor _, name := range names { b.WriteString(name) b.WriteString(", ")}result := b.String()var sb = new StringBuilder();for (String name : names) { sb.append(name).append(", ");}String result = sb.toString();To join with a separator, both have a shortcut: strings.Join(names, ", ") and String.join(", ", names).
Comparing in Java: equals, not ==
== checks whether they are the same object; equals compares the content. Sometimes == “works” because of the string pool, which makes the bug hard to find. In Go, == compares the content.
See also: strings, runes and bytes in Go and Data types.