当前位置: 首页> 科技> 名企 > 怎样开物流网站_长沙平面设计公司都有哪些_发布友情链接_百度seo排名优化如何

怎样开物流网站_长沙平面设计公司都有哪些_发布友情链接_百度seo排名优化如何

时间:2025/7/12 10:23:52来源:https://blog.csdn.net/m0_73558214/article/details/146570683 浏览次数:0次
怎样开物流网站_长沙平面设计公司都有哪些_发布友情链接_百度seo排名优化如何

Go语言结构体详解

引言

在Go语言中,结构体是一种非常重要的数据类型,它允许程序员将不同类型的数据组合在一起,形成一个完整的数据结构。这种特性使得Go语言在处理复杂数据时更加灵活和高效。本文将深入探讨Go语言中结构体的定义、实例化、方法定义以及相关操作,通过丰富的示例代码帮助读者全面理解结构体的使用方法。

自定义类型

在Go语言中,当标准库提供的数据类型无法满足开发需求时,开发人员可以通过type关键字自定义新类型。自定义类型可以基于现有类型,也可以是结构体、接口、函数等复杂类型。

type name string

上述代码基于string类型定义了新的类型name。尽管name类型与string类型的用法相似,但它们是两种独立的类型,不能直接进行比较运算。

var a string = "abcde"
var b name = "abcde"
fmt.Printf("变量a的类型:%T\n", a)
fmt.Printf("变量b的类型:%T\n", b)

输出结果如下:

变量a的类型:string
变量b的类型:main.name

如果尝试直接比较ab,会引发编译错误,因为它们属于不同的类型。

a == b // 错误:类型不同,无法比较

当基于现有类型定义的新类型仍无法满足需求时,可以定义更复杂的类型,如结构体、接口和函数类型。

// 结构体
type car struct {id    uintcolor uint32
}// 接口
type sender interface {writeTo(d string, len int, msg string)
}// 函数
type otherFunc func(x float32) float32

在定义类型时,如果使用了赋值运算符=,则新类型仅仅是现有类型的别名,而不是全新的类型。例如,charint32类型的别名,因此char类型的变量与int32类型的变量可以进行比较运算。

var x char = 'H'
var y int32 = 72
fmt.Printf("x和y变量相等?%t", x == y)

结构体的定义

结构体是一种用户自定义的复合数据类型,它可以将多个不同类型的数据组合在一起,形成一个整体。结构体的定义格式如下:

type <结构体名称> struct {<字段列表>
}

字段列表是可选的,可以定义没有字段成员的结构体,但即使字段列表为空,一对大括号也不能省略。

type atbWorker struct {}

字段成员的定义与变量相似,可以逐个定义,也可以将类型相同的字段写在一起。

type photo struct {pID    uint16width  float32height float32dpi    float32
}// 等价于
type photo struct {pID     uint16width, height, dpi float32
}

若希望结构体的字段成员能被其他包的代码访问,除了结构体自身的名称需要首字母大写外,其字段成员的名称也要首字母大写。

type Order struct {ID        uint64Product   stringDate      time.TimeQty       float32Remarks   string
}

命名中首字母为小写的字段只能在当前包中访问。

type Student struct {StdID   uintName    stringAge     uint8email   string // email字段只能在当前包中使用
}

结构体的实例化

结构体的实例化过程有多种代码格式,总体可归纳为两大类——默认初始化和手动初始化。

默认初始化

当使用var关键字声明结构体类型的变量后,程序会为该结构体的各个字段分配默认值。

type fileInfo struct {name        stringsize        uint64isSysFile   boolcreateTime  int64
}var x fileInfo
fmt.Printf("文件名:%s\n", x.name)
fmt.Printf("文件大小:%d\n", x.size)
fmt.Printf("是否为系统文件:%t\n", x.isSysFile)
fmt.Printf("创建时间:%s\n", time.Unix(x.createTime, 0))

也可以这样写:

var x = fileInfo{}
// 或者
x := fileInfo{}

上面代码虽然为变量赋了值,但没有设置fileInfo实例各字段的值,因此各字段的值仍然为默认值。

手动初始化

结构体实例化后通常需要为字段赋值,可以在定义变量后逐个字段进行赋值,也可以在定义变量时直接初始化字段的值。

var y fileInfo
y.name = "dmd.txt"
y.isSysFile = false
y.size = 6955263
y.createTime = time.Date(2020, 3, 7, 15, 48, 16, 0, time.Local).Unix()

或者在定义变量时直接初始化:

var g = fileInfo{name: "abc.dat",size: 128880,isSysFile: true,createTime: time.Date(2019, 10, 20, 14, 36, 21, 0, time.Local).Unix(),
}

在多行初始化语句中,最后一个字段末尾的逗号不能省略。

var g = fileInfo{name: "abc.dat",size: 128880,isSysFile: true,createTime: time.Date(2019, 10, 20, 14, 36, 21, 0, time.Local).Unix(),
}

许多时候,某些字段的默认值正是所需要的值,这种情况下可以忽略部分字段的赋值。

k := fileInfo{name: "dxy.ts",size: 3006265,createTime: time.Date(2020, 1, 1, 23, 15, 4, 0, time.Local).Unix(),
}

还有一种最简洁的初始化方法:省略字段名称。

var z = fileInfo{"test.dat", 1172363, true, time.Now().Unix()}

赋值的顺序必须与字段在结构体中定义的顺序一致,而且赋值的数量也要与字段的数量相等。

如果变量的类型声明为指针类型,那么可以先创建结构体实例并完成初始化,然后使用取地址运算符&获取其内存地址,再赋值给指针变量。

var c = fileInfo{"sys.dll", 23312, true, time.Now().Unix()}
var pc *fileInfo = &c

也可以合并为一步完成。

var pc *fileInfo = &fileInfo{"sys.dll", 23312, true, time.Now().Unix()}

结构体的方法

结构体的方法对象并不是在结构体的内部定义的,而是在结构体外部以函数的形式定义。方法与一般函数有一点不同,在方法名称前有一个接收参数。该参数传递的是方法所属结构体的实例。

type test struct {
}func (o test) doSomething() string {return "do nothing"
}

方法调用语法如下:

var n test
s := n.doSomething()

在定义方法时,接收的结构体实例也可以是指针类型。

func (o *test) doSomething2() string {return "do nothing - 2"
}

接收结构体实例的参数何时使用指针类型,这取决于应用场景。下面示例可通过对比看出两种传递参数方式的区别。

示例:setIntV1和setIntV2方法

步骤1:定义demo结构体,它包含data字段成员。

type demo struct {data int
}

步骤2:为demo结构体定义两个方法。其中setIntV1方法在接收对象参数时只复制demo实例,而setIntV2方法接收的是demo类型的指针,传递的是实例的内存地址。

func (x demo) setIntV1(n int) {x.data = n // 修改data字段的值
}func (x *demo) setIntV2(n int) {x.data = n // 修改data字段的值
}

步骤3:初始化demo实例。

var a = demo{data: 100}

步骤4:分别调用setIntV1方法和setIntV2方法,并输出调用前后data字段的值。

// 情况一:非指针类型接收demo实例
fmt.Println("---------- 传递demo实例的副本 ----------")
fmt.Printf("调用setIntV1方法前,data字段的值:%d\n", a.data)
// 调用setIntV1方法
a.setIntV1(200)
fmt.Printf("调用setIntV1方法后,data字段的值:%d\n\n", a.data)// 情况二:以指针类型接收demo实例
fmt.Println("---------- 传递demo实例的内存地址 ----------")
fmt.Printf("调用setIntV2方法前,data字段的值:%d\n", a.data)
// 调用setIntV2方法
a.setIntV2(200)
fmt.Printf("调用setIntV2方法后,data字段的值:%d\n", a.data)

步骤5:尝试运行示例,会得到以下输出内容。

---------- 传递demo实例的副本 ----------
调用setIntV1方法前,data字段的值:100
调用setIntV1方法后,data字段的值:100---------- 传递demo实例的内存地址 ----------
调用setIntV2方法前,data字段的值:100
调用setIntV2方法后,data字段的值:200

调用setIntV1方法时,demo实例会将自身复制一份再传递给方法,所以在setIntV1方法内部所修改的是demo实例副本的data字段,而不是原来demo实例(变量a所引用的对象)的data字段。这使得setIntV1方法被调用后,a.data保持原值(100)不变。

调用setIntV2方法时,demo实例将自身的内存地址传递给方法,在方法内部所修改的data字段属于原来的demo实例(变量a所引用的对象)。这期间操作的都是同一个实例,因此在调用完setIntV2方法后,a.data的值会被更新为200。

通过这个示例,可以得出结论:当需要在方法内部修改结构体对象的字段时,应该传递该结构体实例的指针。如果在方法内部只是读取结构体字段的值,那么传递给方法的结构体实例可以是值类型。

实战示例

为了更好地理解结构体的使用,下面通过一个完整的示例代码,展示结构体的定义、实例化和方法的使用。

package mainimport ("fmt""time"
)// 定义一个Person结构体
type Person struct {name   stringage    uint8weight float32height float32gender uint8
}// 定义Person结构体的方法:介绍自己
func (p Person) introduce() string {return fmt.Sprintf("大家好,我叫%s,今年%d岁,体重%.1fkg,身高%.1fm,性别%d。", p.name, p.age, p.weight, p.height, p.gender)
}// 定义Person结构体的方法:更新年龄(指针接收)
func (p *Person) updateAge(newAge uint8) {p.age = newAge
}func main() {// 实例化Person结构体person1 := Person{name:   "张三",age:    25,weight: 70.5,height: 1.75,gender: 1,}// 调用introduce方法fmt.Println(person1.introduce())// 更新年龄person1.updateAge(26)fmt.Println("更新年龄后:", person1.introduce())// 使用指针接收器修改字段person2 := &Person{name:   "李四",age:    30,weight: 65.3,height: 1.68,gender: 0,}person2.updateAge(31)fmt.Println("直接通过指针修改年龄后:", person2.introduce())
}

运行结果:

大家好,我叫张三,今年25岁,体重70.5kg,身高1.75m,性别1。
更新年龄后: 大家好,我叫张三,今年26岁,体重70.5kg,身高1.75m,性别1。
直接通过指针修改年龄后: 大家好,我叫李四,今年31岁,体重65.3kg,身高1.68m,性别0。

在这个示例中,我们定义了一个Person结构体,并为其定义了两个方法:introduceupdateAgeintroduce方法是值接收器,用于返回人物的自我介绍信息;updateAge方法是指针接收器,用于更新人物的年龄。通过这个示例,我们可以看到如何定义结构体、实例化结构体以及调用结构体的方法。

总结

Go语言的结构体是一种强大的数据结构,允许我们将不同类型的数据组合在一起,形成一个完整的数据模型。通过结构体,我们可以更好地组织和管理数据,使代码更加模块化和易于维护。本文详细介绍了Go语言中结构体的定义、实例化、方法定义以及相关操作,并通过丰富的示例代码帮助读者深入理解结构体的使用方法。希望本文能为Go语言学习者提供有价值的参考,帮助大家在实际开发中更高效地使用结构体。

关键字:怎样开物流网站_长沙平面设计公司都有哪些_发布友情链接_百度seo排名优化如何

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: