• 技术文章 >后端开发 >Golang

    golang中有没有类

    青灯夜游青灯夜游2023-01-12 16:56:04原创51

    golang中没有类。golang不是一门纯面向对象编程语言,它没有class(类)的概念,也就没有继承的说法,但Go也可以模拟面向对象的编程方式。在Go中,可以将struct比作其它语言中的class;通过struct定义结构体,表征一类对象,例“type person struct {...}”。

    本教程操作环境:windows7系统、GO 1.18版本、Dell G3电脑。

    面向对象三大特征:封装,继承,多态。

    Go不是一门纯面向对象编程语言,它没有class(类)的概念,也就没有继承的说法。但Go也可以模拟面向对象的编程方式,即可以将struct比作其它语言中的class。

    对象

    Go没有class的概念,通过struct定义结构体,表征一类对象。

    type person struct {
    	Age  int
    	Name string
    }

    对象是状态与行为的有机体。例如下面的java代码:

    public class Person {
    
        int age;
    
        String name;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

    不同于Java,Go的方法不需要跟类的数据绑定在一个class的定义里面,只需要定义在同一个包内。这一点可能初学Go的同学,会感觉很奇怪。

    type person struct {
    	Age  int
    	Name string
    }
    
    func (p *person) GetAge() int {
    	return p.Age
    }
    
    func (p *person) SetAge(age int)  {
    	p.Age = age
    }
    
    func (p *person) GetName() string {
    	return p.Name
    }
    
    func (p *person) SetName(name string) {
    	p.Name = name
    }

    构造函数

    Go没有构造函数,对象的数据载体就是一个struct。Java支持构造函数,构造函数名字就跟类名字一样,多个构造函数通过函数重载实现。

    而Go构造函数则通过工厂函数进行模拟。实例如下:

    type person struct {
    	Age  int
    	Name string
    }
    
    /**
    	构造函数1--通过名字初始化
     */
    func newPersonByName(name string) *person {
    	return &person{
    		Name: name,
    	}
    }
    
    /**
    	构造函数2--通过年龄初始化
     */
    func newPersonByAge(age int) *person {
    	return &person{
    		Age: age,
    	}
    }

    需要注意的是,person结构体的名称首字母要小写,避免外部直接越过模拟的构造函数

    访问权限

    Java有四种访问权限,如下所示:

    java访问控制符
    publicprotected

    friendly

    (default)

    private
    同一个类yesyesyesyes
    同一个包yesyesyesno
    不同包子类yesyesnono
    不同包非子类yesnonono

    Go则做了简化,可见性的最小粒度是包。也就是说,Go保留两种,friendly和public。Go的变量名如果首字母是小写,则代表包内可见;如果首字母是大写,则代表任何地方都可见。

    封装

    封装,把抽象出来的结构体跟操作结构体内部数据的函数绑定在一起。外部程序只能根据导出的函数API(public方法)修改结构体的内部状态。

    封装有两个好处:

    隐藏实现:我们只希望使用者直接使用API操作结构体内部状态,而无需了解内部逻辑。就好像一座冰山,我们只看到它露出水面的那一部分。

    保护数据:我们可以对数据的修改和访问施加安全措施,调用setter方法的时候,我们可以对参数进行校验;调用getter方法,我们可以增加访问日志等等。

    一个简单的bean定义如下所示:

    type person struct {
    	Age  int
    	Name string
    }
    
    func NewPerson(age int, name string) *person{
    	return &person{age, name}
    }
    
    func (p *person) SetAge(age int)  {
    	p.Age = age
    }
    
    func (p *person) SetName(name string) {
    	p.Name = name
    }
    
    func main() {
    	p:= NewPerson(10, "Lily")
    	p.SetName("Lucy")
    	p.SetAge(18)
    }

    需要注意的是,Go的方法是一种特殊的函数,只是编译器的一种语法糖,编译器瞧瞧帮我们把对象的引用作为函数的第一个参数。例如,下面的代码是等价的

    func main() {
    	p:= NewPerson(10, "Lily")
    
    	p.SetName("Lily1")
    	// 等价于下面的写法
    	// p是一个引用,函数引用
    	setNameFunc := (*person).SetName
    	setNameFunc(p, "Lily2")
    	fmt.Println(p.Name)
    }

    继承

    继承,子类继承父类,则获得父类的特征和行为。继承的主要目的是为了重用代码。Java实现代码重用的两大利器,就是继承和组合。

    Go没有class的概念,谈不上继承。但Go可以通过匿名组合来模拟继承。

    如下所示,Cat通过匿名聚合了Animal结构体,就自动获得了Animal的move()和Shout()方法:

    type Animal struct {
    	Name string
    }
    
    func (Animal) move()  {
    	fmt.Println("我会走")
    }
    
    func (Animal) shout()  {
    	fmt.Println("我会叫")
    }
    
    type Cat struct {
    	Animal // 匿名聚合
    }
    
    func main() {
    	cat := &Cat{Animal{"猫"}}
    
    	cat.move()
    	cat.shout()
    }

    多态

    多态,申明为基类的变量,可以在运行期指向不同的子类,并调用不同子类的方法。多态的目的是为了统一实现。

    我们通过接口来实现多态。在java里,我们通过interface来定义接口,通过implements来实现接口。

    interface Animal {
    
        void move();
    
        void shout();
    }
    
    class Dog implements Animal {
    
        @Override
        public void move() {
            System.out.println("我会走");
        }
    
        @Override
        public void shout() {
            System.out.println("我会叫");
        }
    }

    而Go则是通过鸭子类型推断,只要某个对象长得想鸭子,叫起来像鸭子,那么它就是鸭子。也就是说,Go的接口是比较隐匿的,只要某个对象实现来接口申明的所有方法,那么就认为它属于该接口。

    type Animal interface {
    
    	move()
    	shout()
    }
    
    type Cat struct {
    	Animal // 匿名聚合
    }
    
    func (Cat)move()  {
    	fmt.Println("猫会走")
    }
    
    func (Cat)shout()  {
    	fmt.Println("猫会叫")
    }
    
    type Dog struct {
    	Animal  // 匿名聚合
    }
    
    
    func (Dog)move()  {
    	fmt.Println("狗会走")
    }
    
    func (Dog)shout()  {
    	fmt.Println("狗会叫")
    }
    
    func main() {
    	cat := Cat{}
    	dog := Dog{}
        // 申明接口数组
     	animals := []Animal{cat, dog}
    	for _,ele := range animals {
            // 统一访问
    		ele.move()
    		ele.shout()
    	}
    }

    【相关推荐:Go视频教程编程教学

    以上就是golang中有没有类的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐: go语言 Golang
    上一篇:Go语言字符串怎么转为数组 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • go语言中for range是什么结构• Go语言中延迟执行语句是什么• Go语言的词法元素有几类• go语言中变量声明方法有哪些• Go语言error类型是什么
    1/1

    PHP中文网