参考 https://studygolang.com/pkgdoc
1.获取一个页面的html代码并打印输出
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
)
func main() {
//http.Get返回Response对象
//追踪Get函数
// func Get(url string) (resp *Response, err error) {
// return DefaultClient.Get(url)
// }
//追踪DefaultClient
// var DefaultClient = &Client{}
//声明并赋值
//Client实现了Get方法
//我一直奇怪为什么我给了个地址,就能返回一个Response对象
//然后Response对象里的Body就能存储信息,但是Body也是一个io.ReadCloser接口类型,他是怎么存储东西的
res, err := http.Get("https://www.foxzc.com/archives/2020/08/13/359")
if err != nil {
log.Fatal(err)
}
result, err := ioutil.ReadAll(res.Body)
//Body是io.ReadCloser
//io.ReadCloser
res.Body.Close()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", result)//打印数据
}
2.获取一个页面的html代码并保存到文件
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
)
func main() {
//http.Get返回Response对象
//追踪Get函数
// func Get(url string) (resp *Response, err error) {
// return DefaultClient.Get(url)
// }
//追踪DefaultClient
// var DefaultClient = &Client{}
//声明并赋值
//Client实现了Get方法
res, err := http.Get("https://www.foxzc.com/archives/2020/08/13/359")
if err != nil {
log.Fatal(err)
}
result, err := ioutil.ReadAll(res.Body)
//Body是io.ReadCloser
//io.ReadCloser
res.Body.Close()
if err != nil {
log.Fatal(err)
}
//保存到文件
err = ioutil.WriteFile("abc.html", result, 0777)
if err != nil {
log.Fatal(err)
}
}
疑问点
对于我这样的新手来说,很难理解
//我一直奇怪为什么我给了个地址,就能返回一个Response对象
//然后Response对象里的Body就能存储信息,但是Body也是一个io.ReadCloser接口类型,他是怎么存储东西的
然后我写了个例子
package main
import "fmt"
type People struct { //定义一个People结构体类型
Name string
}
type SetName interface { //People类型实现了SetName接口
set()
}
//定义一个函数,接受People类型的参数,返回SetName类型
//这里要注意,因为People类型实现了SetName接口,所以可以把p当成SetName类型,但是反过来就不行,不能把SetName类型当成People类型
func (p People) set() {
p.Name = "张三"
fmt.Println("名字变成:", p.Name)
}
func do(p People) SetName {
p.set()
return p
}
func main() {
var p = People{"李四"}
fmt.Println("p原来是", p)
do(p)
fmt.Println("现在p是", p)
}
// p原来是 {李四}
// 名字变成: 张三
// 现在p是 {李四}
我们发现p没变,因为我们没传指针,他的作用域就只是在函数里,改写下
package main
import "fmt"
type People struct {
Name string
}
type SetName interface {
set()
}
func (p *People) set() {
p.Name = "张三"
fmt.Println("名字变成:", p.Name)
}
func do(p *People) SetName {
p.set()
return p
}
func main() {
var p = &People{"李四"}
fmt.Println("p原来是", p)
do(p)
fmt.Println("现在p是", p)
}
// p原来是 &{李四}
// 名字变成: 张三
// 现在p是 &{张三}
这个例子就是给了一个结构体对象,函数返回的是接口类型,也就是实现了这个接口的对象,这个对象里有数据,也可以再加个函数和People的全局变量,只传一个Name变量给结构体,这样就是上面我的疑问,为什么给个地址就能返回一个对象,再改写下
package main
import "fmt"
type People struct { //定义一个People结构体类型
Name string
}
type SetName interface { //People类型实现了SetName接口
set()
}
//定义一个函数,接受People类型的参数,返回SetName类型
//这里要注意,因为People类型实现了SetName接口,所以可以把p当成SetName类型,但是反过来就不行,不能把SetName类型当成People类型
func (p *People) set() {
p.Name = "张三"
fmt.Println("名字变成:", p.Name)
}
func do(p *People) SetName {
p.set()
return p
}
func setP(n string) *People { //因为是全局变量,DefaultPeople可以直接在函数里用
DefaultPeople.Name = n
return DefaultPeople
}
var DefaultPeople = &People{} //全局变量,就像上面的Client
func main() {
p := setP("李四")
fmt.Println("p原来是", p)
do(p)
fmt.Println("现在p是", p)
}
// p原来是 &{李四}
// 名字变成: 张三
// 现在p是 &{张三}
到这里应该可以理解我之前的疑惑了,再模仿上面的Get方法,传名字返回对象,改写下
package main
import "fmt"
type People struct { //定义一个People结构体类型
Name string
}
type SetName interface { //People类型实现了SetName接口
set()
}
//定义一个函数,接受People类型的参数,返回SetName类型
//这里要注意,因为People类型实现了SetName接口,所以可以把p当成SetName类型,但是反过来就不行,不能把SetName类型当成People类型
func (p *People) set() *People {
p.Name = "张三"
fmt.Println("名字变成:", p.Name)
return p//返回对象
}
// func do(p *People) SetName {
// p.set()
// return p
// }
func setP(n string) *People { //因为是全局变量,DefaultPeople可以直接在函数里用
DefaultPeople.Name = n
return DefaultPeople.set()//结合上面的set方法,这样上面的do就省略了
}
var DefaultPeople = &People{} //全局变量,就像上面的Client
func main() {
p := setP("李四")
fmt.Println(p)
}
// 名字变成: 张三
// &{张三}
以上都是我个人编写的例子,仅供自己理解,也希望可以帮到你,大佬勿喷