go中的重要的点:
- go中是以package为单位进行引用文件 , 一个文件夹下面只有一个package,所以通过引用src下面的文件路径,就可以引用这个package下面的所有的公共的 ==数据结构 ==
- go中所有的数据结构(type) 都可以进行实现接口
- go中所有的 == 数据结构== 都可以作为变量进行传递
建立简单的具有err和panic处理的web接口
-
手法一 : 对核心的函数进行扩展(对err和panic)的处理 and 适配
-
panic的放入和recover的取出错误
-
controller 核心处理请求的逻辑,返回不同的错误
// todo 处理函数只管处理 ,如果有错误就把错误返回, 将错误交给其他人进行处理
const prefix = "/list/"
func Handler (writer http.ResponseWriter, request *http.Request) error{
//todo 查看是否包含这个匹配头
if strings.Index(request.URL.Path,prefix) != 0 {
return userError("Path must start "+ "with "+prefix)
}
path := request.URL.Path[len(prefix):] //todo 取出请求的匹配部分
file, err := os.Open(path)
if err != nil{
return err
}
defer file.Close()
bytes, err := ioutil.ReadAll(file)
if err != nil {
return err
}
writer.Write(bytes)
return nil
}
type userError string
func (u userError) Error() string {
return u.Message()
}
func (u userError) Message() string {
return string(u)
}
- 对核心处理函数的扩展包装 适配
//todo 设置一种函数变量类型
type AppHandler func(http.ResponseWriter, *http.Request) error
//todo 在一种函数类型中进行拓展 修改为另一种函数结构返回; 也算是适配器的功能;
func ErrHandler(app_handler AppHandler) func(http.ResponseWriter, *http.Request){
return func(writer http.ResponseWriter, request *http.Request){
//todo 对panic的兜底处理
defer func() {
r := recover() //todo 从recover中调出错误,兜底对错误进行处理;
if r==nil{
return
}
if err, ok := r.(error); ok {
log.Printf("Error handle request : %s ",err.Error())
http.Error(writer,http.StatusText(http.StatusInternalServerError),http.StatusInternalServerError)
}else{
panic(r)
}
}()
//todo 真正的处理函数的运行
err := app_handler(writer,request)
//todo 自定义的函数的错误处理 ---> 1 usererrinfo handle(根据类型判定是否为user错误) 2 systeminfo handle
if err != nil {
log.Printf("Error handle request : %s ",err.Error())
//todo 面向用户的一些错误的拦截,输出
if userErr,ok :=err.(UserErr); ok {
http.Error(writer,userErr.Message(),http.StatusBadRequest)
return
}
code := http.StatusOK
switch {
case os.IsNotExist(err) :
code = http.StatusNotFound
case os.IsPermission(err):
code = http.StatusForbidden
default:
code = http.StatusInternalServerError
}
http.Error(writer,http.StatusText(code),code)
}
}
}
type UserErr interface{
error //在一个接口中包含的另一个接口 todo 是给系统看的
Message() string //todo 单独的有关用户信息输出的错误 给用户看的
}
- 函数运行
func main() {
http.HandleFunc("/", ErrHandler(fileHandle.Handler))
err := http.ListenAndServe(":8866", nil)
if err != nil {
panic(err)
}
}
go自带代码test
两个部分
- 测试case的成功率,覆盖率
- 测试代码的性能 速度
- 可以查看代码每部分的耗能情况
规范以及实际实现
- 规范
func TestTriangle(t *testing.T){
Test := []struct {
a,b,c int32
}{
{1,2,3},
{0,2,2},
{0,0,0},
{-1,1,0},
{math.MaxInt32,1,math.MinInt32},
}
for _, _ = range Test {
_ =LengthOfLongestSubs("sfdfdsfddsfdsfdsfdfsdfdftring")
}
}
go test . 测试case的通过情况
结果 : ok awesomeProject/learnGo/tableTest 0.005s
- 测试运行的性能 快慢
func BenchmarkSubstr (b *testing.B){
for i:=0;i<b.N ;i++{
_ =LengthOfLongestSubs("sfdfdsfddsfdsfdsfdfsdfdftring")
}
}
go test -bench .
- result :
goos: darwin
goarch: amd64
pkg: awesomeProject/learnGo/tableTest
BenchmarkSubstr-4 2188663 553 ns/op
PASS
ok awesomeProject/learnGo/tableTest 1.770s
代码细节耗能查看
- 查看代码每一部分的耗能情况 go test -bench . -cpuprofile cpu.out 生成一个二进制文件
- go tool pprof cpu.out 进入一个交互式的命令行 —> web