当前位置: 首页 > news >正文

免费流程图制作网站百度站长工具综合查询

免费流程图制作网站,百度站长工具综合查询,网站改造设计方案,“一个”网站面向对象编程 Go语言的面向对象编程和其他语言有非常大的差别。 Go 是一种面向对象的语言吗? 是和不是。虽然 Go 有类型和方法,并允许面向对象的编程风格,但没有类型层次结构(继承)。Go 中的“接口”概念提供了一种不…

面向对象编程

Go语言的面向对象编程和其他语言有非常大的差别。

image-20230428111344935

Go 是一种面向对象的语言吗?

是和不是。虽然 Go 有类型和方法,并允许面向对象的编程风格,但没有类型层次结构(继承)。Go 中的“接口”概念提供了一种不同的方法,我们认为这种方法易于使用,并且在某些方面更通用。还有一些方法可以将类型嵌入到其他类型中,以提供类似于(但不完全相同)子类化的东西。此外,Go 中的方法比 C++ 或 Java 中的方法更通用:它们可以为任何类型的数据定义,甚至是内置类型,例如普通的“未装箱”整数。它们不限于结构(类)。

此外,缺少类型层次结构使得 Go 中的“对象”感觉比 C++ 或 Java 等语言中的“对象”轻量级得多。

封装数据和行为

结构体定义

image-20230428121213526

实例创建及初始化

image-20230428121307421

type Employee struct {Id   stringName stringAge  int
}func TestCreateEmployeeObj(t *testing.T) {e := Employee{"0", "Bob", 20}e1 := Employee{Name: "Mike", Age: 30}e2 := new(Employee) // 返回指针e2.Id = "2"e2.Name = "Rose"e2.Age = 22t.Log(e)t.Log(e1)t.Log(e1.Id)t.Log(e2)t.Logf("e is %T", e)t.Logf("e2 is %T", e2)
}

image-20230428122127640

行为(方法)定义

image-20230428122402465

  • 第一种

    func (e Employee) String() string {fmt.Printf("Address is %x", unsafe.Pointer(&e.Name))fmt.Println()return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age)
    }func TestStructOperations(t *testing.T) {e := Employee{"0", "Bob", 20}fmt.Printf("Address is %x", unsafe.Pointer(&e.Name))fmt.Println()t.Log(e.String())
    }
    

    image-20230428123715323

    所以这种写法会有复制的开销。

  • 第二种

    func (e *Employee) String() string {fmt.Printf("Address is %x", unsafe.Pointer(&e.Name))fmt.Println()return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age)
    }func TestStructOperations(t *testing.T) {e := &Employee{"0", "Bob", 20} // 传递引用fmt.Printf("Address is %x", unsafe.Pointer(&e.Name))fmt.Println()t.Log(e.String())
    }
    

    image-20230428123601046

    更推荐这种。

接口(定义交互协议)

Go的接口和很多主流编程语言的接口有很大的区别。

Java代码的示例:

image-20230428124443597

Duck Type式接口

Go语言的interface:

image-20230428125301615

type Programmer interface {WriteHelloWorld() string
}type GoProgrammer struct {
}func (g *GoProgrammer) WriteHelloWorld() string { // duck type 鸭子类型return "Hello World"
}func TestClient(t *testing.T) {var p Programmerp = new(GoProgrammer)t.Log(p.WriteHelloWorld())
}

image-20230428143644240

Go接口

image-20230428130027398

接口变量

image-20230428130325699

自定义类型

image-20230428130434903

type IntConv func(op int) int// 计算函数操作的时长
func timeSpend(inner IntConv) IntConv { // 以前的方法特别的长 我们可以用自定义类型做替换// 类似装饰者模式,对原来的函数进行了一层包装return func(n int) int {start := time.Now()ret := inner(n)fmt.Println("time spend:", time.Since(start).Seconds())return ret}
}

扩展和复用(类似继承)

Go语言无法天然支持继承,但是又想要实现面向对象的特性。

即父类对象 使用子类对象初始化,那么该父类对象调用的函数就是子类实现的函数 ,从而满足LSP(子类交换原则)。

案例一: Go语言 支持扩展父类的功能,如下代码:

package oriented_testimport ("fmt""testing"
)// Pet 类
type Pet struct {
}func (p *Pet) Speak(){ // Pet类的函数成员fmt.Print("Pet speak.\n")
}func (p *Pet) SpeakTo(host string) { // Pet类的函数成员p.Speak()fmt.Println("Pet SpeakTo ", host)
}// Dog 扩展Pet的功能
type Dog struct {p *Pet
}// 扩展父类的方法
func (d *Dog) Speak(){d.p.Speak()
}// 扩展父类的方法
func (d *Dog) SpeakTo(host string) {d.Speak()fmt.Println("Dog Speakto ", host)
}func TestDog(t *testing.T) {dog := new(Dog)dog.SpeakTo("Test dog")
}

以上测试代码的输出如下:

image-20230428141543094

dog 的 SpeakTo 中调用了 dog 的 Speak,其中调用了 Pet 的 Speak,所以输出正常。
Pet 和 Dog 调用不会相互影响,完全由用户决定。

但是这和我们所想需要的不同,Pet 类有自己的方法,Dog 类有自己的方法,两者作用域完全不同。

这里Go语言推出了匿名嵌套类型,即 Dog 类不用实现自己的和 Pet 类同名的方法即可,通过在 Dog 类的声明中变更 Pet 成 员。

匿名嵌套类型

案例二: Go语言支持匿名函数类型

// Dog 扩展Pet的功能
type Dog struct {Pet
}

这样即不需要 Dog 声明自己的同名函数成员,默认的调用即为 Pet 成员函数的调用。

package oriented_testimport ("fmt""testing"
)type Pet struct {
}func (p *Pet) Speak(){fmt.Print("Pet speak.\n")
}func (p *Pet) SpeakTo(host string) {p.Speak()fmt.Println("Pet SpeakTo ", host)
}// Dog 扩展Pet的功能
type Dog struct {Pet // 支持匿名嵌套类型
}func TestDog(t *testing.T) {var dog Dogdog.Speak()dog.SpeakTo("Test dog")
}

最终的输出如下:

image-20230428141503654

调用的都是 Pet 的成员函数,感觉像是继承了,因为继承默认就是子类能够使用父类的公有成员。

在匿名嵌套类型下,我们想要完整尝试一下Go语言是否真正支持继承,可以像之前的代码一样在 Dog 中实现 Pet 的同名函数,且能够通过父类对象调用子类的成员方法,像 C++/Java 这样进行向上类型转换(本身是不可能的,Go语言不支持显式类型转换)。

案例三: Go语言不支持继承,如下代码:

package oriented_testimport ("fmt""testing"
)type Pet struct {
}func (p *Pet) Speak(){fmt.Print("Pet speak.\n")
}func (p *Pet) SpeakTo(host string) {p.Speak()fmt.Println("Pet SpeakTo ", host)
}// Dog 扩展Pet的功能
type Dog struct {//p *PetPet // 支持匿名嵌套类型
}// 重载父类的方法
func (d *Dog) Speak(){fmt.Print("Dog speak.\n")
}// 重载父类的方法
func (d *Dog) SpeakTo(host string) {d.Speak()fmt.Println("Dog Speakto ", host)
}func TestDog(t *testing.T) {var dog Pet = new(Dog) // 这里就会编译错误dog.Speak()dog.SpeakTo("Test dog")
}
cannot use new(Dog) (value of type *Dog) as Pet value in variable declaration
不支持将Pet类型转换为Dog类型

总结一下,Go语言并不支持继承,能够支持接口的扩展 和 复用**(匿名嵌套类型)**,内嵌这种方式是完全不能当成继承来用的,因为它不支持访问子类的方法数据(重载),不支持LSP原则。

其中扩展 就是不同类实现相同的成员函数,能够实现类似于案例一中的扩展接口形态。

复用则是通过匿名嵌套类型实现 类似于重载的功能,可以看看案例二的代码。

多态

image-20230428143317910

type Programmer interface {WriteHelloWorld() string
}type GoProgrammer struct {
}func (g *GoProgrammer) WriteHelloWorld() string {return "fmt.Println(\"Hello World\")"
}type JavaProgrammer struct {
}func (j *JavaProgrammer) WriteHelloWorld() string {return "System.out.println(\"Hello World\")"
}// 多态
func writeFirstProgram(p Programmer) {fmt.Printf("%T %v\n", p, p.WriteHelloWorld())
}func TestClient(t *testing.T) {goProgrammer := new(GoProgrammer)javaProgrammer := new(JavaProgrammer)writeFirstProgram(goProgrammer)writeFirstProgram(javaProgrammer)
}

image-20230428144147613

空接口与断言

image-20230428144326958

func DoSomething(p interface{}) {// '.' 断言,p.(int),p断言为int类型if i, ok := p.(int); ok {fmt.Println("Integer", i)return}if s, ok := p.(string); ok {fmt.Println("string", s)return}fmt.Println("UnKnow type")
}func TestEmptyInterface(t *testing.T) {DoSomething(10)DoSomething("10")DoSomething(10.00)
}

image-20230428145558309

Go接口最佳实践

image-20230428145718339

错误机制

error

image-20230428150518369

package errorimport ("errors""testing"
)func GetFibonacci(n int) ([]int, error) {if n < 2 || n > 100 {return nil, errors.New("n should be in [2, 100]")}fibList := []int{1, 1}for i := 2; i < n; i++ {fibList = append(fibList, fibList[i-1]+fibList[i-2])}return fibList, nil
}func TestGetFibonacci(t *testing.T) {if v, err := GetFibonacci(-10); err != nil {t.Error(err)} else {t.Log(v)}
}

image-20230428161919642

最佳实践

image-20230428162534768

尽早失败,避免嵌套!

例:

func GetFibonacci2(str string) {var (i    interr  errorlist []int)if i, err = strconv.Atoi(str); err != nil {fmt.Println("Error", err)return}if list, err = GetFibonacci(i); err != nil {fmt.Println("Error", err)return}fmt.Println(list)
}

panic

image-20230428163230055

panic vs os.Exit

image-20230428163307433

revocer

image-20230428164252392

recover 类似于 java 的 catch

func TestRecover(t *testing.T) {defer func() {if err := recover(); err != nil {fmt.Println("recovered from", err)}}()fmt.Println("Start")panic(errors.New("something wrong"))
}

image-20230428183030584

image-20230428165703129

其实上面这种修复方式是非常危险的。

我们一定要当心自己 revocer 在做的事,因为我们 revocer 并不检测到底发生了什么错误,而只是记录了一下或者直接忽略掉了,这时可能系统某些核心资源消耗完了,但我们把他强制恢复之后系统依然是不能正常工作的,还会导致我们的健康检查程序 health check 检查不出当前系统的问题,因为很多 health check 只是检查当前系统的进程在还是不在, 因为我们的进程是在的,所以就会形成僵尸进程,它还活着,但它不能提供服务。

image-20230428165726627

如果出现了这种问题,我们可以用 “Let is Crash” 可恢复的设计模式,我们直接 crash 掉,这样守护进程就会重新把服务进程提起来(说的有点高大上,其实就是重启),重启是恢复不确定性错误的最好方法。

包 package

构建可复用的模块(包)

image-20230428183701611

image-20230428185412938

my_series.go

package seriesfunc GetFibonacci(n int) ([]int, error) {ret := []int{1, 1}for i := 2; i < n; i++ {ret = append(ret, ret[i-1]+ret[i-2])}return ret, nil
}

package_test.go

引用另一个包中的方法:

package clientimport ("mygoland/geekvideo/ch13/series" // 包路径要从自己的gopath开始写起"testing"
)func TestPackage(t *testing.T) {t.Log(series.GetFibonacci(10))
}

init方法

image-20230428185555174

func init() {fmt.Println("init1")
}func init() {fmt.Println("init2")
}func GetFibonacci(n int) []int {ret := []int{1, 1}for i := 2; i < n; i++ {ret = append(ret, ret[i-1]+ret[i-2])}return ret
}

image-20230428185810992

如何使用远程的package

image-20230428192434197

ConcurrentMap for GO

https://github.com/easierway/concurrent_map

使用 go get 命令导入

go get -u github.com/easierway/concurrent_map

image-20230428192052651

package remoteimport (cm "github.com/easierway/concurrent_map" // 导入远程包"testing"
)func TestConcurrentMap(t *testing.T) {m := cm.CreateConcurrentMap(99)m.Set(cm.StrKey("key"), 10)t.Log(m.Get(cm.StrKey("key")))
}

image-20230428192409198

依赖管理

Go未解决的依赖问题

image-20230429184940847

vendor路径

image-20230429185019589

常用的依赖管理工具

  • godep:https://github.com/tools/godep
  • glide:https://github.com/Masterminds/glide
  • dep:https://github.com/golang/dep

安装glide

  • mac环境,使用 brew 安装 glide

    brew install glide
    

    安装成功
    image-20230430132905106

  • 初始化 glide

    glide init
    

    image-20230505090852387

    image-20230505092905006

    image-20230505093034649

    image-20230505093114018

    image-20230505093146424

    image-20230505093229266

    image-20230505093327934

  • glide init 执行完毕后,生成了一个 yaml 文件,并把依赖的包和版本号定义在了里面

    image-20230505093453057

  • 在之前的目录下执行glide install

    image-20230505094627270

    然后就会在我们的指定的文件下面生成一个 vender 目录和 glide.lock 文件。

    image-20230505094650525

  • 到此为止,Go 就能 搜索到 vender 目录下面的 package 了,我们就通过 vender 来指定了包的路径和版本号,即实现了在同一环境下使用同一个包的不同版本依赖了。

笔记整理自极客时间视频教程:Go语言从入门到实战

http://www.yayakq.cn/news/490260/

相关文章:

  • 西安网站 技术支持牛商网网站seo关键字
  • 重庆做网站怎么做如何做企业介绍
  • 域名注册后网站建设如何做好校园推广
  • 网站租用服务器费用同步编辑wordpress
  • 做印量调查的网站安远做网站
  • 中国建设银行网站是什么东莞品牌网站设计公司计公司
  • 大连建设网站公司WordPress文章多图分页
  • 做网站架构需要注意什么WordPress极简博客主题
  • 网站建设个人工作总结深圳网站开发工程师
  • 大连 手机网站案例网站制作需要多少钱官网
  • 做淘宝优惠网站如何做网站店铺的模板
  • 易烊千玺个人网站入口wordpress 解密成md5
  • 网站宣传有文化事业建设费吗深圳比较好的网站设计公司
  • 江苏住房建设厅网站wordpress批量修改图片tag
  • 网站建设公司活动襄樊网站建设公司
  • 郏县建设局网站计算机网站开发要考什么证
  • x网站免费网站建设前期策划
  • 深圳网站设计 建设元wordpress前台显示英文
  • python django 做 网站手机 网站 开发
  • 无锡建设局官方网站网站建设工作领导小组
  • pc端和移动端的网站区别是什么秦皇岛网站制作专家
  • 做商城网站带宽外贸软件都是怎么收费的
  • 如何网站专题策划wordpress回到顶部
  • 东莞 网站制作百度网盘提取码入口
  • 宁波产品网站设计模板央企网站群建设中标公告
  • 网站技能培训做刷赞网站能赚钱吗
  • 怎么看网站是否织梦福建网站开发公司
  • 做网站客户没有付定金网推渠道平台
  • 做网站的有什么软件苏州人才网
  • 外贸网站google推广wordpress注册页面修改