前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >golang学习笔记之二 - 面向对象基础

golang学习笔记之二 - 面向对象基础

作者头像
躺平程序员老修
发布2023-09-05 16:11:47
1230
发布2023-09-05 16:11:47
举报

学习笔记 golang

面向对象基础

  • struct基础:自定义类型,Go支持只提供类型,而不写字段名的方式,也就是匿名字段,也称为嵌入字段。当匿名字段是一个struct的时候,那么这个struct所拥有的全部字段都被隐式地引入了当前定义的这个struct。
代码语言:javascript
复制
// 定义一个 人类 struct
type person struct {
    name string
    age int
}

// 定义一个 学生 struct,继承了人类struct
type student struct {
    person    // 匿名字段
    class1 int
    tercherName string
}

func s1()  {
    var p1 person
    p1.age = 22
    p1.name = "John"
    fmt.Println(p1)

    p2 := person{name:"Jack", age:55}
    fmt.Println(p2)
}

func s2()  {
    var student = student{person{"小红", 18}, 8, "陈老师"}
    fmt.Println(student)
    student.tercherName = "老李"
    fmt.Println(student.name, student.person.name)
}

func main()  {
    s1()
    s2()
}
  • 属于struct的方法(类内的方法)

假如要计算面积,一般思路如下方法一所示:但是areaRectangle()不是作为Rectangle的方法实现的(类似面向对象里面的方法),而是将Rectangle的对象(如r1,r2)作为参数传入函数计算面积的,那么如果增加一个图形,想计算面积就只能增加新的函数,函数名也必须要跟着更换,变成area_rectangle, area_circle, area_triangle...。用面向对象的思想来说,面积应该是对象的一个方法Rectangle.area(),而非外围函数。

代码语言:javascript
复制
type Rectangle struct {
    width, height float64
}

type Cricle struct {
    radius float64
}

func areaRectangle(r Rectangle) float64  {
    return r.height * r.width
}

//func areaCricle(c Cricle) float64  {
//    // 计算公式等等...
//}

func main()  {
    // 计算长方形面积方法一
    // 如果有多个不同的形状如圆形,就需再写一个外部方法来计算,由此引出方法二:写一个从属struct的方法
    var rec1 = Rectangle{4, 9}
    res1 := areaTest(rec1)
    fmt.Println(res1)
}

定义method语法:func (r ReceiverType) funcName(parameters) (results),则如上例子可以用下面method来实现

代码语言:javascript
复制
type Rectangle struct {
    width, height float64
}

type Cricle struct {
    radius float64
}

func (r Rectangle) area() float64 {
    return r.width * r.height
}

func (c Cricle) area() float64  {
    return c.radius * c.radius * math.Pi
}

func main()  {
    var rectangle = Rectangle{3, 5}
    var cricle = Cricle{10}

    fmt.Println(rectangle.area())
    fmt.Println(cricle.area())
}

注意 :虽然method的名字一模一样,但是主体不一样,那么method就不一样;method里面可以访问接收者的字段;默认情况下方法的Receiver(即类主体)是值传递,而非引用,在method里改变字段是不影响原类的,method同样支持传递引用;调用method通过.访问,就像struct里面访问字段一样。

代码语言:javascript
复制
func (r *Rectangle) area2() float64 {
    r.width = 10             // 问题:这里为什么没用 *r.width = 10 ?
    return r.width * r.height
}

// 先调用area2,发现rectangle已经被更改了,因为传递了引用
fmt.Println(rectangle.area2())
fmt.Println(rectangle)

问题解答: 如果一个method的receiver是T,你可以在一个T类型的实例变量V上面调用这个method,而不需要&V去调用这个method;如果一个method的receiver是T,你可以在一个T类型的变量P上面调用这个method,而不需要 *P去调用这个method;所以不用担心你是调用的指针的method还是不是指针的method,Go已经帮你搞定了。

method继承:如果匿名字段实现了一个method,那么包含这个匿名字段的struct也能调用该method

代码语言:javascript
复制
type Rectangle struct {
    width, height float64
}

type someStruct struct {
    Rectangle    // 继承rectangle,则可以调用所有方法
    params int
}

s1 := someStruct{Rectangle{5, 8}, 10}
fmt.Println(s1.area())    // 40
fmt.Println(s1)           // {{5 8} 10}

method 重写:

代码语言:javascript
复制
type Rectangle struct {
    width, height float64
}

type someType struct {
    Rectangle
    deep float64
}

func (r Rectangle) area(x float64) (res float64)  {
    // 在函数定义了返回值就不需要在函数内重重新声明,直接return即可
    // var res float64
    if x > 0 {
        res = r.width * r.height * x
    } else {
        res = r.width * r.height
    }

    return
}

// 重写area方法
func (s someType) area(x float64) (res float64)  {
    if x > 0 {
        res = s.width + s.height + x
    } else {
        res = s.width + s.height
    }

    return
}

var someType = someType{Rectangle{2, 5}, 3}
fmt.Println(someType)                        // {{2 5} 3}
fmt.Println(someType.Rectangle.area(1))      // 10
fmt.Println(someType.area(1))                // 8

interface

interface可以理解为是一组method签名的组合,我们通过interface来定义对象的一组行为。

代码语言:javascript
复制
// 学生接口 interface就是一组抽象方法的集合
type studentInterface interface {
    sayHi()
    sing()
    //changeSchool(schoolName string)
}

// Human 结构体
type Human struct {
    name string
    age int
    phone string
}

// Student结构体,继承Human
type Student struct {
    Human
    school string
    grade int
}

// Human 对象实现Sayhi方法
func (human Human) sayHi() {
    fmt.Printf("hi, i am %s, and i am %d, call me %s", human.name, human.age, human.phone)
}

// Human 对象实现Sing方法
func (human Human) sing() {
    fmt.Println("lalalalala")
}

// Human 对象实现Guzzle方法
func (human Human) Guzzle(beerStein string) {
    fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}

// student 重载Human的sayHi方法
func (student Student) sayHi() {
    fmt.Println("hi im a student, my name is", student.name, "grade is", student.grade)
}

// student 重载Human的sing方法
//func (student Student) sing() {
//    fmt.Println("lala")
//}

// student 实现转学方法
func (student *Student) changeSchool(schoolName string) {
    student.school = schoolName
}

// 执行方法
func interfaceTest()  {
    var studentI studentInterface

    var Tom = Student{Human{"tom", 18, "13000000000"},"北京大学", 8}
    var John = Human{"shyzhen", 26, "14526555544"}

    // 对象必须完全实现了interface定义的方法才能赋值 可多不可少。如Student同时实现了changeSchool方法,接口中并未定义。
    studentI = Tom
    studentI.sayHi()
    studentI.sing()

    studentI = John
    studentI.sayHi()
    studentI.sing()

    Tom.sayHi()
    Tom.sing()
    Tom.changeSchool("清华大学")
    fmt.Println(Tom)
    John.sayHi()
    John.sing()
}

由于所有的类型都实现了空interface,一个函数把interface{}作为参数,那么他可以接受任意类型的值作为参数,如果一个函数返回interface{},那么也就可以返回任意类型的值。

代码语言:javascript
复制
func interfaceTest2(params interface{}) interface{} {
    return params
}
fmt.Println(interfaceTest2("sssss"))
fmt.Println(interfaceTest2(2323))
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 面向对象基础
  • interface
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档