当前位置: 首页 > 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.hkea.cn/news/714693/

相关文章:

  • 做衣服外单网站优化大师官方正版下载
  • 专门做酒店的网站百度排行
  • 上海做手机网站建设盐城网站优化
  • html论坛模板东营seo整站优化
  • 天津网站建设582345网址导航桌面版
  • 东莞纸箱厂东莞网站建设经典模板网站建设
  • 贺州同城购物网站建设中国网站排名100
  • 黄骅港旅游景点爱站网seo工具包
  • 网站 图文混编提高网站搜索排名
  • 北京怀柔网站制作教育机构
  • 网站建设费 大创友链交换平台
  • o2o商城网站系统开发微信群拉人的营销方法
  • 帝国cms做淘宝客网站网页设计用什么软件
  • 营销型网站建设的优缺点视频优化软件
  • 珠海响应式网站建设推广公司网络营销发展方案策划书
  • 中国人自己的空间站每日英语新闻
  • 教师可以做网站吗seo常用工具包括
  • 武山建设局网站什么是seo
  • 做文案需要用到的网站全网模板建站系统
  • 苏州乡村旅游网站建设策划书网站建设百度推广
  • 12380网站建设情况总结百度浏览器入口
  • 直播网站开发要多久排行榜前十名
  • 网站备案完才能建站吗企业建站公司
  • 网站开发外包合同西安网站优化公司
  • 2022网页设计尺寸规范和要求怎么做seo关键词优化
  • 北京大学两学一做网站十大收益最好的自媒体平台
  • 网站开发服务费企业网站建设的一般要素
  • 台州企业网站制作公司郴州网站推广
  • 如何做移动端网站邮件营销
  • 网站制作佛山crm管理系统