-
Notifications
You must be signed in to change notification settings - Fork 1
/
binary-strings.go
85 lines (74 loc) · 3.39 KB
/
binary-strings.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package main
import (
"bytes"
"fmt"
)
// Strings in Go allow arbitrary bytes. They are implemented basically as
// immutable byte slices and syntactic sugar. This program shows functions
// required by the task on byte slices, thus it mostly highlights what
// happens behind the syntactic sugar. The program does not attempt to
// reproduce the immutability property of strings, as that does not seem
// to be the intent of the task.
func main() {
// Task point: String creation and destruction.
// Strings are most often constructed from literals as in s := "binary"
// With byte slices,
b := []byte{'b', 'i', 'n', 'a', 'r', 'y'}
fmt.Println(b) // output shows numeric form of bytes.
// Go is garbage collected. There are no destruction operations.
// Task point: String assignment.
// t = s assigns strings. Since strings are immutable, it is irrelevant
// whether the string is copied or not.
// With byte slices, the same works,
var c []byte
c = b
fmt.Println(c)
// Task point: String comparison.
// operators <, <=, ==, >=, and > work directly on strings comparing them
// by lexicographic order.
// With byte slices, there are standard library functions, bytes.Equal
// and bytes.Compare.
fmt.Println(bytes.Equal(b, c)) // prints true
// Task point: String cloning and copying.
// The immutable property of Go strings makes cloning and copying
// meaningless for strings.
// With byte slices though, it is relevant. The assignment c = b shown
// above does a reference copy, leaving both c and b based on the same
// underlying data. To clone or copy the underlying data,
d := make([]byte, len(b)) // allocate new space
copy(d, b) // copy the data
// The data can be manipulated independently now:
d[1] = 'a'
d[4] = 'n'
fmt.Println(string(b)) // convert to string for readable output
fmt.Println(string(d))
// Task point: Check if a string is empty.
// Most typical for strings is s == "", but len(s) == 0 works too.
// For byte slices, "" does not work, len(b) == 0 is correct.
fmt.Println(len(b) == 0)
// Task point: Append a byte to a string.
// The language does not provide a way to do this directly with strings.
// Instead, the byte must be converted to a one-byte string first, as in,
// s += string('z')
// For byte slices, the language provides the append function,
z := append(b, 'z')
fmt.Printf("%s\n", z) // another way to get readable output
// Task point: Extract a substring from a string.
// Slicing syntax is the for both strings and slices.
sub := b[1:3]
fmt.Println(string(sub))
// Task point: Replace every occurrence of a byte (or a string)
// in a string with another string.
// Go supports this with similar library functions for strings and
// byte slices. Strings: t = strings.Replace(s, "n", "m", -1).
// The byte slice equivalent returns a modified copy, leaving the
// original byte slice untouched,
f := bytes.Replace(d, []byte{'n'}, []byte{'m'}, -1)
fmt.Printf("%s -> %s\n", d, f)
// Task point: Join strings.
// Using slicing syntax again, with strings,
// rem := s[:1] + s[3:] leaves rem == "bary".
// Only the concatenation of the parts is different with byte slices,
rem := append(append([]byte{}, b[:1]...), b[3:]...)
fmt.Println(string(rem))
}