Go 结构体

Go结构体

结构体是将多个容易类型的命令变量组合在一起的聚合数据类型。

每个变量都成为该结构体的成员变量。

可以理解为Go语言的结构体struct和其他语言的class有相等的地位,但是Go语言放弃大量面向对象的特性,所有的Go语言类型除了指针类型外,都可以有自己的方法,提高了可扩展性。

案例:

package main
import "fmt"

type Person struct{
    Name string
    Age int
} 

func main(){
    var p1 Person
    p1.Name = "Yven"
    p1.age = 19
    fmt.Println(p1.Name,p2.age)
}

成员变量

访问控制机制

如果一个结构体的成员变量名称是首字母大写的,那么这个变量是可导出的。(即在其他包可以访问到)

一个结构体可以同时包含可导出和不可到处的成员变量。

type Person struct {
    Name string  //不可导出
    age int      // 可导出
}

限制

命名结构体类型s不可以定义一个拥有相同结构体类型s的成员变量,也就是一个聚合类型不可以包含它自己。但是s中可以定义一个s的指针类型,即*s。

type Person struct {
    Name string
    p1 Person    //错误
    p2 *person   //正确
}

结构内嵌(匿名字段)

Go语言中没有像java,python中继承的概念,不过他有一个类似的功能,结构内嵌。

案例:

package main
import "fmt"

type Person struct{
    Name string
    Age int
} 

type Student struct{
    Person
    Class string
}

func main(){
    var stu Student
    stu.Name = "Yven"
    stu.Age = 20
    stu.Class = "计算机152"
    fmt.Println(stu.Name, stu.Age, stu.Class)
}

如果嵌入结构的字段和外部结构的字段相同,那么,想要修改嵌入结构的字段值需要加上外部结构中声明的嵌入结构名称。

案例:

package main
import "fmt"

type Person struct{
    Name string
    Age int
} 

type Student struct{
    Person
    Class string
    Name string
}

func main(){
    var stu Student
    stu.Name = "Yven"
    stu.Person.Name = "Yven_lae"
    stu.Age = 20
    stu.Class = "计算机152"
}

Go语言中没有构造方法,但是可以通过工厂模式来解决这个问题,案例如下:

package main
import "fmt"

type Person struct{
    Name string
    Age int
} 

func NewPerson(name string,age int) *Person{
    person := &Person{name,age}
    return person
}

func main(){
    p := NewPerson("Yven", 18)
    fmt.Println(p.name, p.age) //输出 Yven 18
}

方法

Go中除了指针和interface以外的所有类型都可以有方法,不仅仅是struct

方法的定义方式:

func (r ReceiverType) funcName(parameters)(results)

简单案例验证所有类型都可以拥有方法:

package main
import "fmt"

type Int int //没办法直接使用int来进行验证,不过可以对int进行封装后来测试

func (a Int) compare(b Int) bool}{
    return a < b
}

func main(){
    a := 2
    b := 5
    fmt.Println(a.compare(b))
}

方法的声明和普通函数的声明类似,知识在函数名字前面多加了一个参数,这个参数把这个方法绑定在该参数对应的类型上。该参数成为方法的接受者

案例:

type Person struct{
    Name string
    Age int
}

func (p Person) eat(n string){
    fmt.Printf("%v 吃了 %v",p.Name,n)
}

指针接受者的方法

由于主调函数会复制每一个实参变量,或者如果一个实参太大而我们希望避免复制整个实参,因此我们必须使用指针来传递变量的地址。这也同样适用于更新接收者我们将它绑定到指针类型。在调用方法的时候,编译器会对变量进行隐式转换。
总结一下结构体方法可以成功调用的条件:

  • 实参接收者和形参接收者是同一类型,比如都是T或者都是*T。(1,4,5,7)
  • 实参接收者是T类型的变量而形参接收者是*T类型,编译器会隐式的获取变量的地址(3)。
  • 实参接收者是T类型而形参接收者是T类型,编译器会隐式的获取实际的取值。(2,6)其中8编译过程报错的原因是:编译器对T类型转化为T类型的隐式转化,只有实参接收者是变量才可以成功,因为无法获取临时变量的地址。
type Point struct {
    X int
    Y int
}

func (p Point) Print() {
    fmt.Println(p.X, p.Y)
}

func (p *Point) ScaleBy(factor int) {
    p.X *= factor
    p.Y *= factor
}

func main() {
    p := Point{1,1}
    ptr := &p
    p.Print()   //1. 正确
    ptr.Print() //2. 正确
    p.ScaleBy(2)      //3. 正确
    ptr.ScaleBy(2)    //4. 正确
    Point{1,1}.Print()    //5. 正确
    (&Point{1,1}).Print() //6. 正确
    (&Point{1,1}).ScaleBy( 2) //7. 正确
    Point{1,1}.ScaleBy( 2)    //8. 错误
}

原文地址:https://www.cnblogs.com/louyefeng/p/11316903.html

时间: 2024-11-02 15:50:12

Go 结构体的相关文章

关于结构体

1.结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,叫做结构. typedef struct People { int a; char b; double c; }P: 其中:struct是关键词, People是标签, a b c是成员, P是此结构体声明的变量. 于是在声明变量的时候就可:P p1; 这里的P实际上就是struct People的别名.P==struct People 另外这里也可以不写People(于是也不能struct People p1;了,

Linux C中结构体初始化

    在阅读GNU/Linux内核代码时,我们会遇到一种特殊的结构初始化方式.该方式是某些C教材(如谭二版.K&R二版)中没有介绍过的.这种方式称为指定初始化(designated initializer).下面我们看一个例子,Linux-2.6.x/drivers/usb/storage/usb.c中有这样一个结构体初始化项目: static struct usb_driver usb_storage_driver = { .owner = THIS_MODULE, .name = "

在Swift结构体中如何实现写时复制?

结构体(Struct)在Swift语言中占有重要地位,在Swift标准库中,大约有90%的公开类型都是结构体,包括我们常用的Array.String.Dictionary.结构体相比类,一个最重要的特性就是它是值类型,而类似引用类型.值类型是通过复制值来赋值的,而不是引用同一个内存地址,这样就不存在数据共享的问题,能防止意外的数据改变,并且它是线程安全的. 举一个很简单的例子,在objc中,数组是类,是引用类型,在Swift中,数组是结构体,是值类型.因此下面的代码中: let array1 =

结构体的大小

系统在存储结构体变量时存在地址对齐问题,编译器在编译程序时会遵循两条原则: 一.结构体变量中成员的偏移量必须是成员大小的整数倍: 二.结构体大小必须是所有成员大小的整数倍. 1 #include<stdio.h> 2 3 struct a{ 4 int i; 5 float f; 6 char c; 7 double d; 8 long l; 9 }b; 10 11 int main(){ 12 printf("%d\n",sizeof(b.i));// 4 13 prin

关于OC中直接打印结构体,点(CGRect,CGSize,CGPoint,UIOffset)等数据类型

关于OC直接打印结构体,点(CGRect,CGSize,CGPoint,UIOffset)等数据类型,我们完全可以把其转换为OC对象来进项打印调试,而不必对结构体中的成员变量进行打印.就好比我们可以使用NSStringFromCGRect(CGRect rect)来直接打印一个结构体,其他打印可以参考以下内容 UIKIT_EXTERN NSString *NSStringFromCGPoint(CGPoint point); UIKIT_EXTERN NSString *NSStringFrom

38-oc常用结构体

常用结构体 在开发中苹果推荐我们使用CG开头的结构体, 也就是说NS开头的结构体一般不用 OC中定义一个点,用什么结构体 NSPoint; CGPoint point = NSMakePoint(10, 20); OC中保存物体尺寸的,用什么结构体 NSSize; CGSize size = NSMakeSize(100, 50); OC中保存某个物体的位置和尺寸,用什么结构体 NSRect; CGRect rect = NSMakeRect(10, 20, 100, 50); NSNumber

结构体在固件库中的应用

上次介绍了一般结构体的定义以及引用方法,那么接下来将对结构体在官方固件库是如何具体使用的做出简单说明. 结构体指针成员变量引用方法是通过“→”符号来实现,比如要访问student1结构体指针指向的结构体的成员变量name,那么方法是: stuednt1—>name; 如在STM32官方固件库中对端口使用模式结构体定义如下: typedef enum { GPIO_Mode_AIN = 0x0, //模拟输入模式 GPIO_Mode_IN_FLOATING = 0x04, //浮空输入模式 GPI

C# 定义一个学生的结构体,输入学生信息,学号,姓名,身高,按身高排序输出

class Program { //定义一个结构体 struct student//student就是我们自己造的新数据类型 { public int code;//public修饰符 public string name;//结构体的成员 public decimal height; } static void Main(string[] args) { ArrayList arr = new ArrayList(); for (int i = 0; i < 3; i++) { student

类和结构体

//类  class A {     var a = 0 } let classA = A() classA.a = 12     //虽然classA定义为常量,但是仍然可以修改A类中的变量值;结构体则不可以 //类属于引用类型,结构体属于值类型

C语言结构体及函数传递数组参数示例

注:makeSphere()函数返回Sphere结构体,main函数中,调用makeSphere()函数,传递的第一个参数为数组,传递的数组作为指针. 版权声明:本文为博主原创文章,未经博主允许不得转载.