day9接口 练习7.1-7.4
							parent
							
								
									619a2a8929
								
							
						
					
					
						commit
						726c9c1a14
					
				|  | @ -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) | ||||
| } | ||||
|  | @ -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 | ||||
| } | ||||
|  | @ -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()) | ||||
| } | ||||
|  | @ -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)
 | ||||
| 
 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue