golang封装业务err(结合iris)

golang封装业务err

我们有时在web开发时,仅凭httpStatus以及msg是不方便维护和体现我们的业务逻辑的。所以就需要封装我们自己的业务错误。

  • 自定义biz_err
  • 维护err map:errorResponseMap、errorHttpStatusMap

注意:本文主要以演示为主,主要是让大家熟悉封装自定义错误的思路,故而封装的较为简单。大家可根据自己公司需求来进行拓展。

代码仓库地址:https://github.com/ziyifast/ziyifast-code_instruction

项目结构:
在这里插入图片描述

1 err:自定义err,重写打印格式等

1.1 biz_err_demo/error/zerr/errors.go:new方法

  1. 重写控制台打印格式
  2. 封装new方法
  • DefaultBizWrap:不含原始err
  • BizWrap:包含原始err
package zerr

import (
	"errors"
	"fmt"
	"io"
)

func New(message string) error {
	return &fundamental{
		msg:   message,
		stack: callers(),
	}
}

func Errorf(format string, args ...interface{}) error {
	return &fundamental{
		msg:   fmt.Sprintf(format, args...),
		stack: callers(),
	}
}

type fundamental struct {
	msg string
	*stack
}

func (f *fundamental) Error() string { return f.msg }

func (f *fundamental) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			io.WriteString(s, f.msg)
			f.stack.Format(s, verb)
			return
		}
		fallthrough
	case 's':
		io.WriteString(s, f.msg)
	case 'q':
		fmt.Fprintf(s, "%q", f.msg)
	}
}

func WithStack(err error) error {
	if err == nil {
		return nil
	}
	return &withStack{
		err,
		callers(),
	}
}

type withStack struct {
	error
	*stack
}

func (w *withStack) Cause() error { return w.error }

func (w *withStack) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			fmt.Fprintf(s, "%+v", w.Cause())
			w.stack.Format(s, verb)
			return
		}
		fallthrough
	case 's':
		io.WriteString(s, w.Error())
	case 'q':
		fmt.Fprintf(s, "%q", w.Error())
	}
}

func Wrap(err error, message string) error {
	if err == nil {
		return nil
	}
	err = &withMessage{
		cause: err,
		msg:   message,
	}
	return &withStack{
		err,
		callers(),
	}
}

func Trace(err error) error {
	return Wrapf(err, "")
}

func Wrapf(err error, format string, args ...interface{}) error {
	if err == nil {
		return nil
	}
	err = &withMessage{
		cause: err,
		msg:   fmt.Sprintf(format, args...),
	}
	return &withStack{
		err,
		callers(),
	}
}

func WithMessage(err error, message string) error {
	if err == nil {
		return nil
	}
	return &withMessage{
		cause: err,
		msg:   message,
	}
}

func WithMessagef(err error, format string, args ...interface{}) error {
	if err == nil {
		return nil
	}
	return &withMessage{
		cause: err,
		msg:   fmt.Sprintf(format, args...),
	}
}

type withMessage struct {
	cause error
	msg   string
}

func (w *withMessage) Error() string {
	return w.msg + ": " + w.cause.Error()
}

func (w *withMessage) Cause() error {
	return w.cause
}

func (w *withMessage) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			fmt.Fprintf(s, "%+v\n", w.Cause())
			io.WriteString(s, w.msg)
			return
		}
		fallthrough
	case 's', 'q':
		io.WriteString(s, w.Error())
	}
}

func Cause(err error) error {
	type causer interface {
		Cause() error
	}

	for err != nil {
		cause, ok := err.(causer)
		if !ok {
			break
		}
		err = cause.Cause()
	}
	return err
}

func WithCode(err error, code string) error {
	if err == nil {
		return nil
	}
	return &ErrWrap{
		cause: err,
		code:  code,
	}
}

func WithCodef(err error, format string, args ...interface{}) error {
	if err == nil {
		return nil
	}
	return &ErrWrap{
		cause: err,
		code:  fmt.Sprintf(format, args...),
	}
}

type ErrWrap struct {
	cause error
	code  string
	vars  []string
}

func (w *ErrWrap) Vars() []string {
	return w.vars
}

func (w *ErrWrap) Code() string {
	return w.code
}

func (w *ErrWrap) Error() string {
	var msg string
	if w.cause != nil {
		msg += w.cause.Error()
	}
	return msg
}

func (w *ErrWrap) Cause() error {
	return w.cause
}

// Format rewrite format
func (w *ErrWrap) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			fmt.Fprintf(s, "%+v\n", w.Cause())
			io.WriteString(s, "BizCode=["+string(w.code)+"]")
			return
		}
		fallthrough
	case 's', 'q':
		io.WriteString(s, w.Error())
	}
}

func BizWrap(err error, code string, message string, vars ...string) error {
	if err == nil {
		return nil
	}
	codeErr := &ErrWrap{
		cause: err,
		code:  code,
		vars:  vars,
	}
	err = &withMessage{
		cause: codeErr,
		msg:   message,
	}
	return &withStack{
		err,
		callers(),
	}
}

func DefaultBizWrap(code string, vars ...string) error {
	err := errors.New("")
	codeErr := &ErrWrap{
		cause: err,
		code:  code,
		vars:  vars,
	}
	err = &withMessage{
		cause: codeErr,
	}
	return &withStack{
		err,
		callers(),
	}
}

1.2 biz_err_demo/error/zerr/stack.go:堆栈打印格式

定义堆栈打印格式

package zerr

import (
	"fmt"
	"io"
	"path"
	"runtime"
	"strings"
)

type Frame uintptr

func (f Frame) pc() uintptr { return uintptr(f) - 1 }

func (f Frame) file() string {
	fn := runtime.FuncForPC(f.pc())
	if fn == nil {
		return "unknown"
	}
	file, _ := fn.FileLine(f.pc())
	return file
}

func (f Frame) line() int {
	fn := runtime.FuncForPC(f.pc())
	if fn == nil {
		return 0
	}
	_, line := fn.FileLine(f.pc())
	return line
}

func (f Frame) Format(s fmt.State, verb rune) {
	switch verb {
	case 's':
		switch {
		case s.Flag('+'):
			pc := f.pc()
			fn := runtime.FuncForPC(pc)
			if fn == nil {
				io.WriteString(s, "unknown")
			} else {
				file, _ := fn.FileLine(pc)
				fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
			}
		default:
			io.WriteString(s, path.Base(f.file()))
		}
	case 'd':
		fmt.Fprintf(s, "%d", f.line())
	case 'n':
		name := runtime.FuncForPC(f.pc()).Name()
		io.WriteString(s, funcname(name))
	case 'v':
		f.Format(s, 's')
		io.WriteString(s, ":")
		f.Format(s, 'd')
	}
}

type StackTrace []Frame

func (st StackTrace) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		switch {
		case s.Flag('+'):
			for _, f := range st {
				fmt.Fprintf(s, "\n%+v", f)
			}
		case s.Flag('#'):
			fmt.Fprintf(s, "%#v", []Frame(st))
		default:
			fmt.Fprintf(s, "%v", []Frame(st))
		}
	case 's':
		fmt.Fprintf(s, "%s", []Frame(st))
	}
}

type stack []uintptr

func (s *stack) Format(st fmt.State, verb rune) {
	switch verb {
	case 'v':
		switch {
		case st.Flag('+'):
			for _, pc := range *s {
				f := Frame(pc)
				fmt.Fprintf(st, "\n%+v", f)
			}
		}
	}
}

func (s *stack) StackTrace() StackTrace {
	f := make([]Frame, len(*s))
	for i := 0; i < len(f); i++ {
		f[i] = Frame((*s)[i])
	}
	return f
}

func callers() *stack {
	const depth = 32
	var pcs [depth]uintptr
	n := runtime.Callers(3, pcs[:])
	if n > 1 {
		n = 1
	}
	var st stack = pcs[0:n]
	return &st
}

func funcname(name string) string {
	i := strings.LastIndex(name, "/")
	name = name[i+1:]
	i = strings.Index(name, ".")
	return name[i+1:]
}

1.3 biz_err_demo/error/zerr/wrap.go:判断err类型

由自定义err,判断是否属于某个err

package zerr

import (
	"errors"
	"reflect"
)

func Unwrap(err error) error {
	u, ok := err.(interface {
		Cause() error
	})
	if !ok {
		return errors.Unwrap(err)
	}
	return u.Cause()
}

func Is(err, target error) bool {
	if target == nil {
		return err == target
	}

	isComparable := reflect.TypeOf(target).Comparable()
	for {
		if isComparable && err == target {
			return true
		}
		if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
			return true
		}
		if err = Unwrap(err); err == nil {
			return false
		}
	}
}

func As(err error, target interface{}) bool {
	if target == nil {
		panic("errors: target cannot be nil")
	}
	val := reflect.ValueOf(target)
	typ := val.Type()
	if typ.Kind() != reflect.Ptr || val.IsNil() {
		panic("errors: target must be a non-nil pointer")
	}
	targetType := typ.Elem()
	if targetType.Kind() != reflect.Interface && !targetType.Implements(errorType) {
		panic("errors: *target must be interface or implement error")
	}
	for err != nil {
		if reflect.TypeOf(err).AssignableTo(targetType) {
			val.Elem().Set(reflect.ValueOf(err))
			return true
		}
		if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
			return true
		}
		err = Unwrap(err)
	}
	return false
}

var errorType = reflect.TypeOf((*error)(nil)).Elem()

1.4 biz_err_demo/error/biz_err/code.go:业务错误码

自定义业务错误码、对应错误信息及对应错误对应的httpStatusCode

package biz_err

import (
	"myTest/demo_home/biz_err_demo/error/zerr"
	"net/http"
	"strings"
)

const (
	Undefined                 = "Undefined"
	OsCreateFileError         = "OsCreateFileError"
	ImageNotSupported         = "ImageNotSupported"
	UsernameOrPasswordInValid = "UsernameOrPasswordInValid"
)

var errorResponseMap = map[string]string{
	OsCreateFileError:         "创建文件失败",
	ImageNotSupported:         "图片格式不支持",
	UsernameOrPasswordInValid: "用户名或密码错误",
}

var errorHttpStatusMap = map[string]int{
	OsCreateFileError:         http.StatusInternalServerError,
	ImageNotSupported:         http.StatusInternalServerError,
	UsernameOrPasswordInValid: http.StatusInternalServerError,
}

func ParseBizErr(err error) (httpStatus int, code, msg string) {
	if err == nil {
		code = Undefined
	}
	vars := make([]string, 0)
	errWrap := new(zerr.ErrWrap)
	var cause error
	if as := zerr.As(err, &errWrap); as {
		code = errWrap.Code()
		cause = errWrap.Cause()
		vars = errWrap.Vars()
	} else {
		code = Undefined
	}
	if code == Undefined {
		var undefinedMsg string
		if err != nil {
			undefinedMsg = err.Error()
		}
		if undefinedMsg == "" || undefinedMsg == ": " {
			undefinedMsg = errorResponseMap[code]
		}
		return errorHttpStatusMap[code], code, undefinedMsg
	}
	if status, ok := errorHttpStatusMap[code]; ok {
		httpStatus = status
	} else {
		httpStatus = http.StatusOK
	}
	if bizMsg, ok := errorResponseMap[code]; ok {
		for _, v := range vars {
			bizMsg = strings.Replace(bizMsg, "%s", v, 1)
		}
		msg = bizMsg
		if cause != nil {
			_, _, causeMsg := ParseBizErr(cause)
			if causeMsg != "" {
				msg += ", " + causeMsg
			} else {
				msg += ", " + errWrap.Error()
			}
		}
	} else {
		msg = errWrap.Error()
	}
	return httpStatus, code, msg
}

func ErrResponse(err error) (httpStatus int, code, msg string) {
	if err == nil {
		code = Undefined
	}
	vars := make([]string, 0)
	errWrap := new(zerr.ErrWrap)
	var cause error
	if as := zerr.As(err, &errWrap); as {
		code = errWrap.Code()
		cause = errWrap.Cause()
		vars = errWrap.Vars()
	} else {
		code = Undefined
	}
	if status, ok := errorHttpStatusMap[code]; ok {
		httpStatus = status
	} else {
		httpStatus = http.StatusOK
	}
	if bizMsg, ok := errorResponseMap[code]; ok {
		for _, v := range vars {
			bizMsg = strings.Replace(bizMsg, "%s", v, 1)
		}
		msg = bizMsg
		if cause != nil {
			_, _, causeMsg := ErrResponse(cause)
			if causeMsg != "" {
				msg += causeMsg
			} else {
				msg += errWrap.Error()
			}
		}
	} else {
		msg = errWrap.Error()
	}
	return httpStatus, code, msg
}

2 controller:封装base_controller

2.1 biz_err_demo/constant/constant.go

package constant

const (
	ContentTypeJson = "application/json"
	ContentTypeXml  = "application/xml"
)

2.2 biz_err_demo/controller/base_controller.go

package controller

import (
	"encoding/json"
	"encoding/xml"
	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/mvc"
	"github.com/sirupsen/logrus"
	"myTest/demo_home/biz_err_demo/constant"
	"myTest/demo_home/biz_err_demo/error/biz_err"
	"myTest/demo_home/biz_err_demo/response"
	"net/http"
)

type BaseController struct {
	Ctx iris.Context
}

func commonResp(errMsg string, httpCode int, returnCode response.Code, content interface{}) mvc.Response {
	payload := &response.JsonResponse{
		Code:    returnCode,
		Msg:     errMsg,
		Content: content,
	}

	contentDetail, err := json.Marshal(payload)
	if err != nil {
		logrus.Infof("marshal json response error %v", err)
	}

	return mvc.Response{
		Code:        httpCode,
		Content:     contentDetail,
		ContentType: constant.ContentTypeJson,
	}
}

func (c *BaseController) Xml(httpCode int, content interface{}) mvc.Response {
	payload, err := xml.Marshal(content)
	if err != nil {
		logrus.Errorf("marshal xml response error %v", err)
	}
	return c.XmlRaw(httpCode, payload)
}

func (c *BaseController) XmlOK(content interface{}) mvc.Response {
	payload, err := xml.Marshal(content)
	if err != nil {
		logrus.Errorf("marshal xml response error %v", err)
	}
	return c.XmlRaw(http.StatusOK, payload)
}

func (c *BaseController) XmlRaw(httpCode int, content []byte) mvc.Response {
	return mvc.Response{
		Code:        httpCode,
		Content:     content,
		ContentType: constant.ContentTypeXml,
	}
}

func (c *BaseController) JsonBizError(err error) mvc.Response {
	httpStatus, code, msg := biz_err.ErrResponse(err)
	return commonResp(msg, httpStatus, response.Code(code), nil)
}

2.3 biz_err_demo/controller/test_biz_controller.go

package controller

import (
	"errors"
	"github.com/kataras/iris/v12/mvc"
	"myTest/demo_home/biz_err_demo/error/biz_err"
	"myTest/demo_home/biz_err_demo/error/zerr"
	"myTest/demo_home/biz_err_demo/response"
	"net/http"
)

type TestBizController struct {
	BaseController
}

func (t *TestBizController) BeforeActivation(b mvc.BeforeActivation) {
	b.Handle(http.MethodGet, "/testBizErr", "TestBizErr")
}

func (t *TestBizController) TestBizErr() mvc.Result {
	err1 := errors.New("")
	err := zerr.BizWrap(err1, biz_err.UsernameOrPasswordInValid, "")
	return response.JsonBizError(err)
}

3 封装response

3.1 biz_err_demo/response/json_response.go

package response

import (
	"encoding/json"
	"github.com/kataras/iris/v12/mvc"
	"github.com/sirupsen/logrus"
	"myTest/demo_home/biz_err_demo/constant"
	"myTest/demo_home/biz_err_demo/error/biz_err"
)

type Code string

type JsonResponse struct {
	Code    Code        `json:"code"`
	Msg     string      `json:"msg"`
	Content interface{} `json:"content,omitempty"`
}

func JsonBizError(err error) mvc.Response {
	httpStatus, code, msg := biz_err.ErrResponse(err)
	return commonResp(msg, httpStatus, Code(code), nil)
}

func commonResp(errMsg string, httpCode int, returnCode Code, content interface{}) mvc.Response {
	payload := &JsonResponse{
		Code:    returnCode,
		Msg:     errMsg,
		Content: content,
	}

	contentDetail, err := json.Marshal(payload)
	if err != nil {
		logrus.Errorf("%v", err)
	}

	return mvc.Response{
		Code:        httpCode,
		Content:     contentDetail,
		ContentType: constant.ContentTypeJson,
	}
}

4 测试效果

4.1 biz_err_demo/test/main.go

package main

import (
	"errors"
	"github.com/sirupsen/logrus"
	"myTest/demo_home/biz_err_demo/error/biz_err"
	"myTest/demo_home/biz_err_demo/error/zerr"
)

func init() {
	logrus.SetReportCaller(true) // 设置日志是否记录被调用的位置,默认值为 false
}

func main() {
	TestWithNoSourceErr()
	TestWithSourceErr()
	TestParseBizErr()
}

func TestWithNoSourceErr() {
	err := zerr.DefaultBizWrap(biz_err.UsernameOrPasswordInValid, "")
	logrus.Errorf("TestWithNoSourceErr %+v", err)
}

func TestWithSourceErr() {
	err := errors.New("invalid image")
	err = zerr.BizWrap(err, biz_err.ImageNotSupported, "")
	logrus.Errorf("TestWithSourceErr %+v", err)
}

func TestParseBizErr() {
	err := errors.New("")
	err = zerr.BizWrap(err, biz_err.ImageNotSupported, "")
	httpStatus, bizCode, msg := biz_err.ParseBizErr(err)
	logrus.Errorf("httpStatus:%d bizCode:%s msg:%s", httpStatus, bizCode, msg)
}

在这里插入图片描述

4.2 biz_err_demo/main.go

package main

import (
	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/mvc"
	"myTest/demo_home/biz_err_demo/controller"
)

func main() {
	app := iris.New()
	mvc.New(app).Handle(new(controller.TestBizController))
	app.Listen(":8088", nil)
}

在这里插入图片描述

这样前端就能直接根据我们的业务错误码展示对应msg信息

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/354414.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ArcGIS微课1000例】0095:横向图例制作案例教程

文章目录 一、加载数据二、高程分级显示三、横向图例四、注意事项一、加载数据 为了便于直观演示,本实验加载一个栅格数据(配套实验数据包中的0095.rar)并进行分级显示,效果如下: 二、高程分级显示 双击dem数据图层,打开栅格数据的【图层属性】对话框,切换到【符号系统…

POJ No.1852 Ants

思路分析 “转向”问题 假设蚂蚁A与蚂蚁B相遇后转向&#xff0c;可以视作A&#xff0c;B交换位置&#xff0c;从而消除转向。 距离问题 最长距离&#xff1a;比较每只蚂蚁距两端的最大距离&#xff0c;取两端中最大值&#xff0c;取一组中最长距离的最大值。 最短距离&…

互联网加竞赛 基于深度学习的中文情感分类 - 卷积神经网络 情感分类 情感分析 情感识别 评论情感分类

文章目录 1 前言2 情感文本分类2.1 参考论文2.2 输入层2.3 第一层卷积层&#xff1a;2.4 池化层&#xff1a;2.5 全连接softmax层&#xff1a;2.6 训练方案 3 实现3.1 sentence部分3.2 filters部分3.3 featuremaps部分3.4 1max部分3.5 concat1max部分3.6 关键代码 4 实现效果4.…

《HTML 简易速速上手小册》第3章:HTML 的列表与表格(2024 最新版)

文章目录 3.1 创建无序和有序列表&#xff08;&#x1f4dd;&#x1f31f;&#x1f44d; 信息的时尚搭配师&#xff09;3.1.1 基础示例&#xff1a;创建一个简单的购物清单3.1.2 案例扩展一&#xff1a;创建一个旅行计划清单3.1.3 案例扩展二&#xff1a;创建一个混合列表 3.2 …

【C++】输入输出、缺省参数、函数重载

目录 C的输入和输出 缺省参数 概念 缺省参数的分类 全缺省参数 半缺省参数 函数重载 概念 C支持函数重载的原理--名字修饰 C的输入和输出 #include<iostream> // std是C标准库的命名空间名&#xff0c;C将标准库的定义实现都放到这个命名空间中 using namespace …

分类预测 | Matlab实现DT决策树多特征分类预测

分类预测 | Matlab实现DT决策树多特征分类预测 目录 分类预测 | Matlab实现DT决策树多特征分类预测分类效果基本描述程序设计参考资料分类效果

详解顺序结构双指针处理算法

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

计算机网络-编制与调制(基带信号 基带传输 宽度信号 宽度传输 编码 调制 )

文章目录 基带信号与宽带信号编码与调制数字数据编码为数字信号数字数据调制为模拟信号模拟数据编码为数字信号模拟数据调制为模拟信号小结 基带信号与宽带信号 信道上传输的信号除了可以分为数字信号和模拟信号&#xff0c;也可以分为基带信号和宽带信号&#xff0c;只是分类…

数据湖技术之平台建设篇2

数据湖技术之平台建设篇1&#xff0c;主要介绍了湖仓平台建设的前三个主要工作&#xff0c;本次主要继续上次的建设工作介绍&#xff0c;聊一聊一站式湖仓服务平台的相关管理能力建设以及针对小文件的处理。 一. 一站式湖仓服务平台的相关管理能力 主要是将相关能力落地到平台…

【c++】拷贝构造函数

1.概念 在现实生活中&#xff0c;可能存在一个与你一样的自己&#xff0c;我们称其为双胞胎 那在创建对象时&#xff0c;可否创建一个与已存在对象一某一样的新对象呢&#xff1f; 拷贝构造函数&#xff1a;只有单个形参&#xff0c;该形参是对本类类型对象的引用(一般常用c…

[BUUCTF 2018]Online Tool(特详解)

这段代码块检查请求中是否设置了HTTP_X_FORWARDED_FOR头部。如果设置了&#xff0c;它将REMOTE_ADDR设置为HTTP_X_FORWARDED_FOR的值。这通常用于处理Web服务器位于代理后面的情况。 如果URL中未设置host参数&#xff0c;它使用highlight_file(__FILE__);来显示PHP文件的源代码…

【算法专题】二分查找(入门)

&#x1f4d1;前言 本文主要是二分查找&#xff08;入门&#xff09;的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日…

华清远见作业第三十四天——C++(第三天)

思维导图&#xff1a; 题目&#xff1a; 设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 代码&#…

【计算机网络】概述|分层体系结构|OSI参考模型|TCP/IP参考模型|网络协议、层次、接口

目录 一、思维导图 二、计算机网络概述 1.计算机网络定义、组成、功能 2.计算机网络分类 3.计算机网络发展历史 &#xff08;1&#xff09;计算机网络发展历史1&#xff1a;ARPANET->互联网 &#xff08;2&#xff09;计算机网络发展历史2&#xff1a;三级结构因特网 …

C++:类 的简单介绍(一)

目录 类的引用&#xff1a; 类的定义&#xff1a; 类的两种定义方式&#xff1a; 成员变量命名规则的建议&#xff1a; 类的访问限定符及封装&#xff1a; 访问限定符 【访问限定符说明】 封装 class与struct的区别&#xff1a; 类的作用域&#xff1a; 类的实例化…

JVM-字节码文件的组成

Java虚拟机的组成 Java虚拟机主要分为以下几个组成部分&#xff1a; 类加载子系统&#xff1a;核心组件类加载器&#xff0c;负责将字节码文件中的内容加载到内存中。 运行时数据区&#xff1a;JVM管理的内存&#xff0c;创建出来的对象、类的信息等等内容都会放在这块区域中。…

机器学习_集成学习之Boosting(提升较弱的模型,以降低弱模型的偏差)

文章目录 介绍AdaBoost算法梯度提升算法(GBDT)极端梯度提升(XGBoost)Bagging 算法与 Boosting 算法的不同之处 介绍 Boosting 的意思就是提升&#xff0c;这是一种通过训练弱学习模型的“肌肉”将其提升为强学习模型的算法。要想在机器学习竞赛中追求卓越&#xff0c;Boosting…

Go语言安装及开发环境配置

目录 官网 国内 Linux(CentOS & Ubuntu)安装 环境变量设置 命令行下开发 开发模式执行 编译 IDE下开发 插件安装 安装依赖工具 运行 常见问题 1、dial tcp 172.217.160.113:443: i/o timeout 2、VS Code不能完美显示zsh问题 官网 访问Golang官网的下载链接&a…

Python tkinter (6) —— Listbox控件

Python的标准Tk GUI工具包的接口 tkinter系列文章 python tkinter窗口简单实现 Python tkinter (1) —— Label标签 Python tkinter (2) —— Button标签 Python tkinter (3) —— Entry标签 Python tkinter (4) —— Text控件 Python tkinter (5) 选项按钮与复选框 目录…

浏览器——HTTP缓存机制与webpack打包优化

文章目录 概要强缓存定义开启 关闭强缓存协商缓存工作机制通过Last-Modified If-Modified-Since通过ETag If-None-Match 不使用缓存前端利用缓存机制&#xff0c;修改打包方案webpack 打包webpack 打包名称优化webpack 默认的hash 值webapck其他hash 类型配置webpack打包 web…