zoukankan      html  css  js  c++  java
  • go语言之面向对象

    Go 语言结构体

    Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。

    结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。

    结构体表示一项记录,比如保存图书馆的书籍记录,每本书有以下属性:

    • Title :标题
    • Author : 作者
    • Subject:学科
    • ID:书籍ID

    定义结构体

    结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体有中有一个或多个成员。type 语句设定了结构体的名称。结构体的格式如下:

    type struct_variable_type struct {
       member definition;
       member definition;
       ...
       member definition;
    }
    

    一旦定义了结构体类型,它就能用于变量的声明,语法格式如下:

    variable_name := structure_variable_type {value1, value2...valuen}
    或
    variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}
    
    package main
    
    import "fmt"
    
    type Books struct {
       title string
       author string
       subject string
       book_id int
    }
    
    
    func main() {
    
        // 创建一个新的结构体
        fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})
    
        // 也可以使用 key => value 格式
        fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})
    
        // 忽略的字段为 0 或 空
       fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})
    }
    

    输出结果为:

    {Go 语言 www.runoob.com Go 语言教程 6495407}
    {Go 语言 www.runoob.com Go 语言教程 6495407}
    {Go 语言 www.runoob.com  0}
    

    访问结构体成员

    如果要访问结构体成员,需要使用点号 . 操作符,格式为:

    结构体.成员名"
    

    结构体类型变量使用 struct 关键字定义,实例如下:

    package main
    
    import "fmt"
    
    type Books struct {
       title string
       author string
       subject string
       book_id int
    }
    
    func main() {
       var Book1 Books        /* 声明 Book1 为 Books 类型 */
       var Book2 Books        /* 声明 Book2 为 Books 类型 */
    
       /* book 1 描述 */
       Book1.title = "Go 语言"
       Book1.author = "www.runoob.com"
       Book1.subject = "Go 语言教程"
       Book1.book_id = 6495407
    
       /* book 2 描述 */
       Book2.title = "Python 教程"
       Book2.author = "www.runoob.com"
       Book2.subject = "Python 语言教程"
       Book2.book_id = 6495700
    
       /* 打印 Book1 信息 */
       fmt.Printf( "Book 1 title : %s
    ", Book1.title)
       fmt.Printf( "Book 1 author : %s
    ", Book1.author)
       fmt.Printf( "Book 1 subject : %s
    ", Book1.subject)
       fmt.Printf( "Book 1 book_id : %d
    ", Book1.book_id)
    
       /* 打印 Book2 信息 */
       fmt.Printf( "Book 2 title : %s
    ", Book2.title)
       fmt.Printf( "Book 2 author : %s
    ", Book2.author)
       fmt.Printf( "Book 2 subject : %s
    ", Book2.subject)
       fmt.Printf( "Book 2 book_id : %d
    ", Book2.book_id)
    }
    

    以上实例执行运行结果为:

    Book 1 title : Go 语言
    Book 1 author : www.runoob.com
    Book 1 subject : Go 语言教程
    Book 1 book_id : 6495407
    Book 2 title : Python 教程
    Book 2 author : www.runoob.com
    Book 2 subject : Python 语言教程
    Book 2 book_id : 6495700
    

    结构体作为函数参数

    你可以像其他数据类型一样将结构体类型作为参数传递给函数。并以以上实例的方式访问结构体变量:

    package main
    
    import "fmt"
    
    type Books struct {
       title string
       author string
       subject string
       book_id int
    }
    
    func main() {
       var Book1 Books        /* 声明 Book1 为 Books 类型 */
       var Book2 Books        /* 声明 Book2 为 Books 类型 */
    
       /* book 1 描述 */
       Book1.title = "Go 语言"
       Book1.author = "www.runoob.com"
       Book1.subject = "Go 语言教程"
       Book1.book_id = 6495407
    
       /* book 2 描述 */
       Book2.title = "Python 教程"
       Book2.author = "www.runoob.com"
       Book2.subject = "Python 语言教程"
       Book2.book_id = 6495700
    
       /* 打印 Book1 信息 */
       printBook(Book1)
    
       /* 打印 Book2 信息 */
       printBook(Book2)
    }
    
    func printBook( book Books ) {
       fmt.Printf( "Book title : %s
    ", book.title);
       fmt.Printf( "Book author : %s
    ", book.author);
       fmt.Printf( "Book subject : %s
    ", book.subject);
       fmt.Printf( "Book book_id : %d
    ", book.book_id);
    }
    

    以上实例执行运行结果为:

    Book title : Go 语言
    Book author : www.runoob.com
    Book subject : Go 语言教程
    Book book_id : 6495407
    Book title : Python 教程
    Book author : www.runoob.com
    Book subject : Python 语言教程
    Book book_id : 6495700
    

    结构体指针

    你可以定义指向结构体的指针类似于其他指针变量,格式如下:

    var struct_pointer *Books
    

    以上定义的指针变量可以存储结构体变量的地址。查看结构体变量地址,可以将 & 符号放置于结构体变量前:

    struct_pointer = &Book1;
    
    使用结构体指针访问结构体成员,使用 "." 操作符:
    
    struct_pointer.title;
    

    接下来让我们使用结构体指针重写以上实例,代码如下

    package main
    
    import "fmt"
    
    type Books struct {
       title string
       author string
       subject string
       book_id int
    }
    
    func main() {
       var Book1 Books        /* Declare Book1 of type Book */
       var Book2 Books        /* Declare Book2 of type Book */
    
       /* book 1 描述 */
       Book1.title = "Go 语言"
       Book1.author = "www.runoob.com"
       Book1.subject = "Go 语言教程"
       Book1.book_id = 6495407
    
       /* book 2 描述 */
       Book2.title = "Python 教程"
       Book2.author = "www.runoob.com"
       Book2.subject = "Python 语言教程"
       Book2.book_id = 6495700
    
       /* 打印 Book1 信息 */
       printBook(&Book1)
    
       /* 打印 Book2 信息 */
       printBook(&Book2)
    }
    func printBook( book *Books ) {
       fmt.Printf( "Book title : %s
    ", book.title);
       fmt.Printf( "Book author : %s
    ", book.author);
       fmt.Printf( "Book subject : %s
    ", book.subject);
       fmt.Printf( "Book book_id : %d
    ", book.book_id);
    }
    

    以上实例执行运行结果为:

    Book title : Go 语言
    Book author : www.runoob.com
    Book subject : Go 语言教程
    Book book_id : 6495407
    Book title : Python 教程
    Book author : www.runoob.com
    Book subject : Python 语言教程
    Book book_id : 6495700
    
    struct 类似于 java 中的类,可以在 struct 中定义成员变量。
    
    要访问成员变量,可以有两种方式:
    
        1.通过 struct 变量.成员 变量来访问。
        2.通过s truct 指针.成员 变量来访问。
    
        不需要通过 getter, setter 来设置访问权限。
    
        type Rect struct{   //定义矩形类
            x,y float64       //类型只包含属性,并没有方法
            width,height float64
        }
        func (r *Rect) Area() float64{    //为Rect类型绑定Area的方法,*Rect为指针引用可以修改传入参数的值
            return r.width*r.height         //方法归属于类型,不归属于具体的对象,声明该类型的对象即可调用该类型的方法
        }
    

    1、go语言的结构体

    package main
    
    import "fmt"
    
    //go语言没有类,只有结构体,struct,go语言的结构体就相当于python中的类
    
    //定义一个结构体
    //type 结构体名 struct {
    //
    //}
    
    
    
    type Student struct {
    	id int
    	name string
    	sex byte
    	age int
    	addr string
    
    }
    
    
    func main() {
    	//1、顺序实例化一个结构体
    	var s1 Student = Student{}
    
    	fmt.Println(s1)
    	//{1 test1 102 18 beijing}
    
    	s2 := Student{id:2,name:"test2",sex:'m',age:18,addr:"beijing"}
    
    	fmt.Println(s2)
    	//{2 test2 109 18 beijing}
    
    
    	//指定初始化成员,如果有的字段没有赋值,则用默认值代替
    	s3 := Student{id:2,name:"test2",age:18}
    	fmt.Println(s3)
    	//{2 test2 0 18 }
    
    
    	//取结构体中的值,用点来取
    	fmt.Println(s3.age)
    	//18
    
    	//结构体作为指针变量初始化
    
    	var s4 *Student = &Student{id:1,name:"test1",sex:'f',age:18,addr:"beijing"}
    	fmt.Println(s4)
    	//&{1 test1 102 18 beijing}
    
    
    	//下面两种都可以取指针对象的属性
    	fmt.Println((*s4).name)
    	//test1
    	fmt.Println(s4.name)
    	//test1
    
    	//定义一个指针变量的结构体
    	s5 := &Student{id:1,name:"test1",sex:'f',age:18,addr:"beijing"}
    	fmt.Println(s5)
    	//&{1 test1 102 18 beijing}
    
    
    
    }
    

      

    这里我们可以看到,如果传递一个指针进去,可以使用“(&指针name).”的方式调用方法,也可以直接使用"指针name."的方法调用方法,这个是go在内部替我们做了封装

    2、结构体作为参数传递给方法

    package main
    
    
    
    import "fmt"
    
    type Student struct {
    	id int
    	name string
    	sex byte
    	age int
    	addr string
    
    }
    
    //结构体作为参数传递给方法
    //定义一个传递学生对象的方法
    func tmpStuent(tmp Student)  {
    	tmp.id = 250
    	fmt.Println(tmp)
    }
    
    //定义一个传递指针对象的方法
    func tmpStudentobj(p *Student)  {
    	p.id = 249
    	fmt.Println(p)
    }
    
    func main() {
    	var s27_1 Student = Student{id:1,name:"test1",sex:'f',age:18,addr:"beijing"}
    	tmpStuent(s27_1)
    	//{250 test1 102 18 beijing}
    
    	fmt.Println(s27_1)
    	//{1 test1 102 18 beijing}
    
    	tmpStudentobj(&s27_1)
    	//&{249 test1 102 18 beijing}
    	fmt.Println(s27_1)
    	//{249 test1 102 18 beijing}
    
    
    }
    

      

    通过上面的例子我们知道

    如果传递一个结构体给函数,在函数中修改这个结构体,不会影响外面的结构体的值,因为他是重新复制了一份数据

    但是,如果传递一个结构体的指针给函数,在函数中修改这个指针的值,是会影响外面结构体的值的,因为他们是公用一份数据

    3、匿名字段,通过匿名字段来实现继承父类的字段

    package main
    
    import "fmt"
    
    //go语言的面向对象非常的优雅和简单
    //没有封装,多态,继承这些概念,但是同样通过其他方式来实现上面的功能
    
    //封装:通过方法来实现
    //继承:通过匿名字段来实现
    //多态:通过接口来实现
    
    
    type Person struct {
    	name string
    	sex byte
    	age int
    	
    }
    
    type Student1 struct {
    	//匿名字段
    
    	//默认Student_1这个结构体包含了Person这个结构体的所有的字段
    	Person
    	//还可以定义自己私有的字段
    	i int
    	addr string
    
    }
    
    type Student2 struct {
    	//匿名字段
    
    	//默认Student_1这个结构体包含了Person这个结构体的所有的字段
    	Person
    	//还可以定义自己私有的字段
    	i int
    	addr string
    	name string
    
    }
    
    type myint int
    
    type Student3 struct {
    	//自定义类型
    	Person
    
    	//内置类型
    	int
    
    	//自定义类型
    	myint
    }
    
    
    //指针类型的结构体
    type Student4 struct {
    	//匿名字段
    
    	//默认Student_1这个结构体包含了Person这个结构体的所有的字段
    	*Person
    	//还可以定义自己私有的字段
    	i int
    	addr string
    	name string
    
    }
    
    
    
    func main() {
    	//使用匿名字段初始化一个子类
    	s28_1 := Student1{Person:Person{name:"test1",sex:'m',age:18},addr:"beijing",i:1}
    	fmt.Println(s28_1)
    
    	//打印的结构是一个结构体包含一个结构体
    	//{{test1 109 18} 1 beijing}
    
    
    	//这里如果不这样写就会报错Person:Person
    	//mixture of field:value and value initializers
    
    
    	//同名字段的情况
    
    	//如果有同名字段,则默认是就近原则
    	var test28_2 Student2
    	//test28_2.name = "test"
    	//fmt.Println(test28_2)
    	//{{ 0 0} 0  test}
    
    	//如果要想给父类的name赋值怎么做
    
    	test28_2.Person.name = "abc"
    	fmt.Println(test28_2)
    	//{{abc 0 0} 0  }
    
    
    
    	//所有的内置类型和自定义类型都可以作为匿名字段使用
    	//我们这里的myint和Python都可以当做一个自定义类型使用
    
    	test28_3 := Student3{Person:Person{name:"test1",sex:'m',age:18},int:1,myint:2}
    	fmt.Println(test28_3)
    	//{{test1 109 18} 1 2}
    
    	fmt.Println(test28_3.myint)
    	//2
    
    	//指针类型的匿名字段
    	s28_4 := Student4{Person:&Person{name:"test1",sex:'m',age:18},addr:"beijing",i:1}
    
    	fmt.Println(s28_4)
    	//{0x1f43e0e0 1 beijing }
    
    
    	fmt.Println(s28_4.age,"11")
    	//18 11
    }
    

      

      

     匿名字段实现继承

    package main
    
    import "fmt"
    
    type Student struct {
    	sid int
    	name string
    	age int
    	sex byte
    	addr string
    
    }
    
    
    
    type Student1 struct {
    	Student
    
    	hobby string
    	addr int
    
    }
    var s1 Student = Student{
    	sid:1,
    	name:"test",
    	age:12,
    	sex:'m',
    	addr:"sz",
    }
    
    
    
    
    func test10_1(s Student)  {
    	s.name = "test10_1"
    	fmt.Println(s)
    }
    
    func test10_2(s *Student)  {
    	s.name = "test10_2"
    	fmt.Println(s)
    }
    
    
    func main()  {
    	fmt.Println(s1)
    	fmt.Println(s1.name)
    
    	//这种方式必须在函数中使用
    	s2 := Student{sid:1,name:"test2",age:13,sex:'f',addr:"nmg"}
    	fmt.Println(s2)
    
    	s3 := Student{age:13,sex:'f',addr:"nmg"}
    
    	//如果在有未传的变量,则go会给一个默认值
    	fmt.Println(s3.name,s3.sid,s3.addr)
    
    
    	//定义一个指针类型的结构体变量
    	var s4 *Student = &Student{sid:2,name:"test4",age:14,sex:'f',addr:"nmg1"}
    
    	//通过下面两种方式都可以访问指针变量指向的结构体变量的值
    	fmt.Println(s4.addr)
    	fmt.Println((*s4).addr)
    
    
    	s5 := &Student{sid:2,name:"test4",age:14,sex:'f',addr:"nmg1"}
    	fmt.Println(s5)
    
    
    	//test10_1(s2)
    	//fmt.Println(s2.name)
    
    	test10_2(s5)
    	fmt.Println(s5)
    
    
    
    	s6 := Student1{Student:Student{sid:2,name:"test4",age:14,sex:'f',addr:"nmg1"},hobby:"football",addr:12}
    
    	//通过匿名字段实现继承,默认情况下可以访问父类和自己的字段,但是如果父类的字段和自己的字段是相同的,则默认会访问自己的字段
    	//如果一定要访问父类的字段,则需要这样访问s6.Student.addr
    	fmt.Println(s6.sid,s6.hobby,s6.addr,s6.Student.addr)
    
    
    
    }
    
  • 相关阅读:
    HDU 1863 畅通工程(Kruskal)
    HDU 1879 继续畅通工程(Kruskra)
    HDU 1102 Constructing Roads(Kruskal)
    POJ 3150 Cellular Automaton(矩阵快速幂)
    POJ 3070 Fibonacci(矩阵快速幂)
    ZOJ 1648 Circuit Board(计算几何)
    ZOJ 3498 Javabeans
    ZOJ 3490 String Successor(模拟)
    Java实现 LeetCode 749 隔离病毒(DFS嵌套)
    Java实现 LeetCode 749 隔离病毒(DFS嵌套)
  • 原文地址:https://www.cnblogs.com/bainianminguo/p/10873042.html
Copyright © 2011-2022 走看看