《Mastering Go》第四章笔记
王诗翔 · 2020-08-26
Go 结构体
构建结构体:
package main
import "fmt"
func main() {
type XYZ struct {
X int
Y int
Z int
}
var s1 XYZ
fmt.Println(s1.Y, s1.Z)
p1 := XYZ{23, 12, -2}
p2 := XYZ{Z: 12, Y: 13}
fmt.Println(p1)
fmt.Println(p2)
pSlice := [4]XYZ{}
pSlice[2] = p1
pSlice[0] = p2
fmt.Println(pSlice)
p2 = XYZ{1, 2, 3}
fmt.Println(pSlice)
}
运行:
$ go run ./0036-structures.go
0 0
{23 12 -2}
{0 13 12}
[{0 13 12} {0 0 0} {23 12 -2} {0 0 0}]
[{0 13 12} {0 0 0} {23 12 -2} {0 0 0}]
结构体指针
package main
import "fmt"
type myStructure struct {
Name string
Surname string
Height int32
}
func createStruct(n, s string, h int32) *myStructure {
if h > 300 {
h = 0
}
return &myStructure{n, s, h}
}
func retStructure(n, s string, h int32) myStructure {
if h > 300 {
h = 0
}
return myStructure{n, s, h}
}
func main() {
s1 := createStruct("Mihalis", "Tsoukalos", 123)
s2 := retStructure("Mihalis", "Tsoukalos", 123)
fmt.Println((*s1).Name)
fmt.Println(s2.Name)
fmt.Println(s1)
fmt.Println(s2)
}
运行:
$ go run ./0037-pointerStructure.go
Mihalis
Mihalis
&{Mihalis Tsoukalos 123}
{Mihalis Tsoukalos 123}
new 关键字
sP := new([]aStructure)
new
和make
的区别在于make
创建的变量已经进行了适当的初始化,仅能应用于 maps、channels 和 slices,它不会返回地址(即指针)。
元组
Go 没有支持元组类型,但有隐形的元组实现。
min, _ := strconv.ParseFloat(arguments[1], 64)
下面是一个例子:
package main
import "fmt"
func retThree(x int) (int, int, int) {
return 2 * x, x * x, -x
}
func main() {
fmt.Println(retThree(10))
n1, n2, n3 := retThree(20)
fmt.Println(n1, n2, n3)
n1, n2 = n2, n1
fmt.Println(n1, n2, n3)
x1, x2, x3 := n1*2, n1*n1, -n1
fmt.Println(x1, x2, x3)
}
运行:
$ go run ./0038-tuples.go
20 100 -10
40 400 -20
400 40 -20
800 160000 -400
正则表达式和模式匹配
简单示例,选择列:
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
)
func main() {
arguments := os.Args
if len(arguments) < 2 {
fmt.Println("usage: selectColumn column <file1> [<file2> [...<fileN>]")
os.Exit(1)
}
temp, err := strconv.Atoi(arguments[1])
if err != nil {
fmt.Println("Column value is not an integer:", temp)
return
}
column := temp
if column < 0 {
fmt.Println("Invalid Column number!")
os.Exit(1)
}
for _, filename := range arguments[2:] {
fmt.Println("\t\t", filename)
f, err := os.Open(filename)
if err == nil {
fmt.Printf("error opening file %s\n", err)
continue
}
defer f.Close()
r := bufio.NewReader(f)
for {
line, err := r.ReadString('\n')
if err == io.EOF {
break
} else if err != nil {
fmt.Printf("error reading file %s\n", err)
}
// 这里只切空格,如果是其他分隔符呢?
data := strings.Fields(line)
if len(data) >= column {
fmt.Println(data[column-1])
}
}
}
}
解析 IP:
package main
import (
"bufio"
"fmt"
"io"
"net"
"os"
"path/filepath"
"regexp"
)
func findIP(input string) string {
partIP := "(25[0-5]|2[0-4][0-9]|1[0-9][0-9]?[0-9])"
grammar := partIP + "\\." + partIP + "\\." + partIP + "\\." + partIP
matchMe := regexp.MustCompile(grammar)
return matchMe.FindString(input)
}
func main() {
arguments := os.Args
if len(arguments) < 2 {
fmt.Printf("usage: %s logFile\n", filepath.Base(os.Args[0]))
os.Exit(1)
}
for _, filename := range arguments[1:] {
f, err := os.Open(filename)
if err != nil {
fmt.Printf("error opening %s: %s\n", err)
os.Exit(1)
}
defer f.Close()
r := bufio.NewReader(f)
for {
line, err := r.ReadString('\n')
if err == io.EOF {
break
} else if err != nil {
fmt.Printf("error reading file %s", err)
break
}
ip := findIP(line)
trial := net.ParseIP(ip)
if trial.To4() == nil {
continue
} else {
fmt.Println(ip)
}
}
}
}
字符串
package main
import "fmt"
func main() {
const sLiteral = "\x99\x42\x32\x55\x50\x35\x23\x50\x29\x9c"
fmt.Println(sLiteral)
fmt.Printf("x: %x\n", sLiteral)
fmt.Printf("sLiteral length: %d\n", len(sLiteral))
for i := 0; i < len(sLiteral); i++ {
fmt.Printf("%x ", sLiteral[i])
}
fmt.Println()
fmt.Printf("q: %q\n", sLiteral)
fmt.Printf("+q: %+q\n", sLiteral)
fmt.Printf(" x: % x\n", sLiteral)
fmt.Printf("s: As a string: %s\n", sLiteral)
const s3 = "ab12AB"
fmt.Println("s3:", s3)
fmt.Printf("x: % x\n", s3)
fmt.Printf("s3 length: %d\n", len(s3))
for i := 0; i < len(s3); i++ {
fmt.Printf("%x ", s3[i])
}
fmt.Println()
}
rune 和 unicode
package main
import (
"fmt"
"unicode"
)
func main() {
const SL = "\x99\x00ab\x50\x00\x23\x50\x29\x9c"
for i := 0; i < len(SL); i++ {
if unicode.IsPrint(rune(SL[i])) {
fmt.Printf("%c\n", SL)
} else {
fmt.Println("Not printable!")
}
}
}
强大的 strings 包:
package main
import (
"fmt"
s "strings"
)
var f = fmt.Printf
func main() {
upper := s.ToUpper("Hello World!")
f("To Upper: %s\n", upper)
f("To Lower: %s\n", s.ToLower("Hello THERE"))
f("EqualFold: %v\n", s.EqualFold("Mihalis", "MIHAlis"))
f("EqualFold: %v\n", s.EqualFold("Mihalis", "MIHAli"))
// s.HasPrefix()
// s.HasSuffix()
// s.Index()
// s.Count()
// s.Repeat()
// s.TrimSpace()
// s.TrimLeft()
// s.TrimRight()
// s.Compare()
// s.Fields()
// s.Split()
// s.Replace()
// s.Join()
}
switch 语句
package main
import (
"fmt"
"os"
"regexp"
"strconv"
)
func main() {
arguments := os.Args
if len(arguments) < 2 {
fmt.Println("usage: switch number")
os.Exit(1)
}
number, err := strconv.Atoi(arguments[1])
if err != nil {
fmt.Println("This value is not an integer:", number)
} else {
switch {
case number < 0:
fmt.Println("Less than zero!")
case number > 0:
fmt.Println("Greater than zero!")
default:
fmt.Println("Zero!")
}
}
aaString := arguments[1]
switch aaString {
case "5":
fmt.Println("Five!")
case "0":
fmt.Println("Zero!")
default:
fmt.Println("Do not care!")
}
var negative = regexp.MustCompile(`-`)
var floatingPoint = regexp.MustCompile(`d?\.\d`)
var email = regexp.MustCompile(`^[^@]+@[^@.]+\.[^@.]+`)
switch {
case negative.MatchString(aaString):
fmt.Println("Negative number")
case floatingPoint.MatchString(aaString):
fmt.Println("Floating point")
case email.MatchString(aaString):
fmt.Println("It is an email")
fallthrough
default:
fmt.Println("Something else")
}
var aType error = nil
switch aType.(type) {
case nil:
fmt.Println("It is nil interface")
default:
fmt.Println("Not nil interface")
}
}
命令展示 key/value
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
type myElement struct {
Name string
Surname string
Id string
}
var DATA = make(map[string]myElement)
func ADD(k string, n myElement) bool {
if k == "" {
return false
}
if LOOKUP(k) == nil {
DATA[k] = n
return true
}
return false
}
func DELETE(k string) bool {
if LOOKUP(k) != nil {
delete(DATA, k)
return true
}
return false
}
func LOOKUP(k string) *myElement {
_, ok := DATA[k]
if ok {
n := DATA[k]
return &n
} else {
return nil
}
}
func CHANGE(k string, n myElement) bool {
DATA[k] = n
return true
}
func PRINT() {
for k, d := range DATA {
fmt.Printf("key: %s value: %v\n", k, d)
}
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
text := scanner.Text()
text = strings.TrimSpace(text)
tokens := strings.Fields(text)
switch len(tokens) {
case 0:
continue
case 1:
tokens = append(tokens, "")
tokens = append(tokens, "")
tokens = append(tokens, "")
tokens = append(tokens, "")
case 2:
tokens = append(tokens, "")
tokens = append(tokens, "")
tokens = append(tokens, "")
case 3:
tokens = append(tokens, "")
tokens = append(tokens, "")
case 4:
tokens = append(tokens, "")
}
switch tokens[0] {
case "PRINT":
PRINT()
case "STOP":
return
case "DELETE":
if !DELETE(tokens[1]) {
fmt.Println("Delete operation failed!")
}
case "ADD":
n := myElement{tokens[2], tokens[3], tokens[4]}
if !ADD(tokens[1], n) {
fmt.Println("Add operation failed!")
}
case "LOOKUP":
n := LOOKUP(tokens[1])
if n != nil {
fmt.Printf("%v\n", *n)
}
case "CHANGE":
n := myElement{tokens[2], tokens[3], tokens[4]}
if !CHANGE(tokens[1], n) {
fmt.Println("Update operation failed!")
fmt.Println("Unknown command - please try again!")
}
default:
fmt.Println("Unknown command - please try again!")
}
}
}