day9接口 练习7.1-7.4

master
独孤伶俜 2022-12-14 22:45:00 +08:00
parent 619a2a8929
commit 726c9c1a14
4 changed files with 256 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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