From 726c9c1a14a293e173b2120c06232e3700510db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8B=AC=E5=AD=A4=E4=BC=B6=E4=BF=9C?= <1184662350@qq.com> Date: Wed, 14 Dec 2022 22:45:00 +0800 Subject: [PATCH] =?UTF-8?q?day9=E6=8E=A5=E5=8F=A3=20=E7=BB=83=E4=B9=A07.1-?= =?UTF-8?q?7.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/study/day9Interface/Practice/7.1.go | 44 +++++++++ src/study/day9Interface/Practice/7.2.go | 32 +++++++ src/study/day9Interface/Practice/7.3.go | 62 +++++++++++++ src/study/day9Interface/Practice/7.4.go | 118 ++++++++++++++++++++++++ 4 files changed, 256 insertions(+) create mode 100644 src/study/day9Interface/Practice/7.1.go create mode 100644 src/study/day9Interface/Practice/7.2.go create mode 100644 src/study/day9Interface/Practice/7.3.go create mode 100644 src/study/day9Interface/Practice/7.4.go diff --git a/src/study/day9Interface/Practice/7.1.go b/src/study/day9Interface/Practice/7.1.go new file mode 100644 index 0000000..830ec6f --- /dev/null +++ b/src/study/day9Interface/Practice/7.1.go @@ -0,0 +1,44 @@ +package main + +import ( + "bufio" + "bytes" + "fmt" +) + +// 使用来自ByteCounter的思路,实现一个针对单词和行数的计数器。你会发现bufio.ScanWords非常的有用。 +type WordsCount int +type LinesCount int + +func (s *WordsCount) Write(p []byte) (n int, err error) { + var sc = bufio.NewScanner(bytes.NewReader(p)) + sc.Split(bufio.ScanWords) + for sc.Scan() { + // 由于是值传递, 这里想改变原调用者的值, 必须使用指针 + *s++ + } + return int(*s), nil +} + +func (s *LinesCount) Write(p []byte) (n int, err error) { + var sc = bufio.NewScanner(bytes.NewReader(p)) + sc.Split(bufio.ScanLines) + for sc.Scan() { + *s++ + } + return int(*s), nil +} + +func main() { + var wc WordsCount + wc.Write([]byte("hello world")) + var lc LinesCount + lc.Write([]byte(`hello +1 +2 +3 +world`)) + fmt.Println(wc, lc) + fmt.Fprintf(&wc, "Hello, %s", "dugulp") + fmt.Println(wc, lc) +} diff --git a/src/study/day9Interface/Practice/7.2.go b/src/study/day9Interface/Practice/7.2.go new file mode 100644 index 0000000..2d53115 --- /dev/null +++ b/src/study/day9Interface/Practice/7.2.go @@ -0,0 +1,32 @@ +package main + +import ( + "bufio" + "bytes" + "io" +) + +// 封装一个结构体, 此结构体不对外导出 +// 内部的两个元素同样是不对外导出的, 只能通过CountingWriter方法获取 +type countWriter struct { + w io.Writer + c *int64 +} + +func (c countWriter) Write(p []byte) (n int, err error) { + var sc = bufio.NewScanner(bytes.NewReader(p)) + sc.Split(bufio.ScanWords) + for sc.Scan() { + // 由于是值传递, 这里想改变原调用者的值, 必须使用指针 + // 此处n++是要计算新增的单词数 + n++ + // 此处c++是总的单词数 + *c.c++ + } + return int(n), nil +} + +func CountingWriter(w io.Writer) (io.Writer, *int64) { + var c int64 + return &countWriter{w, &c}, &c +} diff --git a/src/study/day9Interface/Practice/7.3.go b/src/study/day9Interface/Practice/7.3.go new file mode 100644 index 0000000..756acaa --- /dev/null +++ b/src/study/day9Interface/Practice/7.3.go @@ -0,0 +1,62 @@ +package main + +import "fmt" + +type tree struct { + value int + left, right *tree +} + +// 实现Stringer接口 +func (tree *tree) String() string { + var values []int + values = appendValues(values, tree) + return fmt.Sprint(values) +} + +// Build 构建二叉树 +func Build(nums []int) *tree { + var root *tree + for _, v := range nums { + root = add(root, v) + } + return root +} + +// Sort 排序 +func Sort(values []int) { + var root = Build(values) + // 将二叉树还原为切片 + appendValues(values[:0], root) +} +func appendValues(values []int, t *tree) []int { + if t != nil { + values = appendValues(values, t.left) + values = append(values, t.value) + values = appendValues(values, t.right) + } + return values +} + +// 建树 +func add(t *tree, value int) *tree { + if t == nil { + t = new(tree) + t.value = value + return t + } + if value < t.value { + t.left = add(t.left, value) + //fmt.Println("left", t.value) + } else { + t.right = add(t.right, value) + //fmt.Println("right", t.value) + } + //fmt.Println(value) + return t +} +func main() { + var nums []int = []int{4, 5, 43, 323, 45, 98, 4, 5, 7, 8, 1, 3, 2, 565} + var tree = Build(nums) + fmt.Println(tree.String()) +} diff --git a/src/study/day9Interface/Practice/7.4.go b/src/study/day9Interface/Practice/7.4.go new file mode 100644 index 0000000..fd0d986 --- /dev/null +++ b/src/study/day9Interface/Practice/7.4.go @@ -0,0 +1,118 @@ +package main + +import ( + "fmt" + "golang.org/x/net/html" + "io" + "net/http" + "strings" +) + +type Html interface { + io.ReadCloser + Getdoc(url string) (err error) + ForeachNode(n *html.Node, pre, post func(n *html.Node)) + SearchNode(tag string) []*html.Node + PrintAll() +} + +// 不对外暴露,一切操作均通过方法实现 +// 除了Html接口中定义的方法, 还可以自己拓展方法, 例如Show方法 +type htmlParser struct { + Html + str string + node *html.Node + resp *http.Response +} + +// 自定义读入 +func (doc *htmlParser) Read(p []byte) (n int, err error) { + if len(p) == 0 { + return 0, fmt.Errorf("error, read data is empty") + } + n = copy(p, doc.str) + if doc.node != nil { + return 0, fmt.Errorf("error, node is not empty") + } + doc.node, err = html.Parse(strings.NewReader(doc.str)) + return n, err +} + +// Clear 清空 +func (doc *htmlParser) Clear() { + doc.node = nil + doc.resp = nil +} + +// Close 关闭连接 +func (doc *htmlParser) Close() error { + return doc.resp.Body.Close() +} + +// Getdoc 通过url获取网页内容 +func (doc *htmlParser) Getdoc(url string) (err error) { + doc.resp, err = http.Get(url) + defer doc.Close() // 关闭连接 + if doc.resp.StatusCode != http.StatusOK { + err = fmt.Errorf("http get error: %s", doc.resp.Status) + return err + } + doc.node, err = html.Parse(doc.resp.Body) + if err != nil { + return fmt.Errorf("html parse error: %s", err) + } + return nil +} + +// ForEachNode 遍历节点 +func (doc *htmlParser) ForEachNode(n *html.Node, pre, post func(n *html.Node)) { + if n == nil { + return + } + if pre != nil { + pre(n) + } + doc.ForEachNode(n.FirstChild, pre, post) + doc.ForEachNode(n.NextSibling, pre, post) + if post != nil { + post(n) + } +} + +// SearchNode 搜索节点 +func (doc *htmlParser) SearchNode(tag string) []*html.Node { + var nodes []*html.Node + doc.ForEachNode(doc.node, func(n *html.Node) { + if n.Type == html.ElementNode && n.Data == tag { + nodes = append(nodes, n) + } + }, nil) + return nodes +} + +// PrintAll 打印所有节点 +func (doc *htmlParser) PrintAll() { + doc.ForEachNode(doc.node, func(n *html.Node) { + if n.Type == html.ElementNode { + fmt.Printf("%s\n", n.Data) + } + }, nil) +} + +// Show 是没有定义在接口中的方法,所以只能通过结构体实例调用 +func (doc *htmlParser) Show() { + fmt.Println(doc.resp) + fmt.Println() + fmt.Println(doc.node) +} +func main() { + var doc htmlParser + doc.Getdoc("https://go.dev/") + doc.Show() + // 如果使用接口类型,则不能使用Show方法 + //var doc Html + //doc.Getdoc("https://go.dev/") + // 因为接口类型中没有定义Show方法,所以不能调用 + //doc.Show() // error, Show undefined (type Html has no field or method Show) + +}