golang笔记——struct

1、定义一个结构体

type User struct {
    userid   int
    username string
    password string
}

 

2、初始化一个结构体

  有两种情况,一是得到结构体的对象,一是得到结构的对象指针,分别有三种方式:

 //第1种方式,先声明对象,再初始化
    var player1 Player
    player1.userid = 1
    player1.username = "lina1"
    player1.password = "123456"
  
    //第2种方式,声明同时初始化
    player2 := Player{2, "lina2", "123456"}

    //第3种方式,通过 field:value 形式初始化,该方式可以灵活初始化字段的顺序
    player3 := Player{username: "lina3", password: "123456", userid: 3}

    //上面三种初始化方式都是生产对象的,相应如果想初始化得到对象指针的三种方法如下:
    //第1种方式,使用 new 关键字
    player4 := new(Player)
    player4.userid = 4
    player4.username = "lina4"
    player4.password = "123456"

    //第2种方式,声明同时初始化
    player5 := &Player{5, "lina2", "123456"}

    //第3种方式,通过 field:value 形式初始化,该方式可以灵活初始化字段的顺序
    player6 := &Player{username: "lina3", password: "123456", userid: 6}

 

3、对象与对象指针的区别(更确切的说应该是值类型和指针类型)

  与C/C++类似,GO语言也存在对象与对象的指针,但不同的是,GO语言中没有 -> 操作符来调用指针所属的成员,而与一般对象一样,都是使用 . 来调用。

  对于一个函数(或方法),如果函数的参数(或接收者)是对象指针时,表示此对象是可被修改的;相反的,如果是对象时,表示是不可修改的(但如果该对象本身就是引用类型,如 map\func\chan 等,则本质上是可以修改的)。所以一般的做法是,方法的接收者习惯性使用对象指针,而不是对象,一方面可以在想修改对象时进行修改,另一方面也减少参数传递的拷贝成本。

  另外,有一点尤为特殊,如果是作为函数的参数,则函数定义时,是使用对象还是对象指针,是有本质区别的,在使用对象作为参数的函数中,不能传入对象指针,同样的,在使用对象指针作为参数的函数中,也不能传入对象,否则编译器会报错。但如果是方法,则接收者定义为对象还是对象指针,都可以接收对象和对象指针的调用。下面我们来定义相关的函数和方法如下:

//传入 Player 对象参数
func print_obj(player Player) {
    //player.username = "new"  //修改并不会影响传入的对象本身
    log.Println("userid:", player.userid)
}

//传入 Player 对象指针参数
func print_ptr(player *Player) {
    player.username = "new"
    log.Println("userid:", player.userid)
}

//接收者为 Player 对象的方法,方法接收者的变量,按照 GO 语言的习惯一般不用 this/self ,而是使用接收者类型的第一个小写字母,可以看标准库中的代码风格。
func (p Player) m_print_obj() {
    //p.username = "new"  //修改并不会影响传入的对象本身
   log.Println("self userid:", p.userid) 
} 

//接收者为 Player 对象指针的方法
func (p *Player) m_print_ptr() { 
  p.username = "new" 
  log.Println("self userid:", p.userid) 
}

   然后测试一下函数跟方法的调用:

    print_obj(player2)
    //print_ptr(player2)        //无法调用,编译出错
    player2.m_print_obj()
    player2.m_print_ptr()

    //print_obj(player6)        //无法调用,编译出错
    print_ptr(player6) 
    player6.m_print_obj()
    player6.m_print_ptr()

   既然对于对象与对象指针的区别,方法的处理很特殊,那么将一个对象传入到接收者为对象指针的方法中,及将一个对象指针传入到一个接收者为对象的方法中,能不能修改传入对象的值呢?答案是,由方法的定义决定,而不是方法的调用者类型决定。

 

4、匿名字段

  结构体里的字段可以只有类型名,而没有字段名,这种字段称为匿名字段。匿名字段可以是一个结构体、切片等复合类型,也可以是 int 这样的简单类型。但建议不要把简单类型作为匿名字段。

type Pet struct {
    id      int
    petname string
}

type Player struct {
    id int
    Pet
    int
}

func main() {
    var player1 Player
    player1.petname = "pet1" //可以直接访问匿名字段中的成员,就像访问自己的成员一样
    player1.int = 3          //一般不推荐将简单类型作为匿名字段,如果有多个匿名的int,这里就没法处理了
    player1.id = 1           //如果外层跟内层字段名重复的话,优先取外层字段
    player1.Pet.id = 10      //如果外层跟内层字段名重复的话,可以通过这种形式来访问内层字段
}

 

你可能感兴趣的:(golang笔记——struct)