go——结构
Go语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
结构体定义需要使用type和struct语句。struct语句定义一个新的数据类型,结构体中有一个或多个成员。
type语句设定了结构体的名称。格式如下:
type struct_name struct {
name string
talk Talk
}
一旦定义了结构体类型,它就能用于变量的声明,语法格式如下:
variable_name := structure_name{value1,value2} //顺序必须与结构体的定义一致
或者:
variable_name := structure_name{key1:value1,key2:value2} //结构体名称:值
结构体类型中的每个字段都需要独占一行。一般情况下,字段声明需由字段名称和表示字段类型的字面量组成。
还有一种只有类型字面量的无名称字段,称为嵌入字段。
虽然嵌入字段可以用来无缝集成额外字段和方法,但是其嵌入规则和使用规则都比较复杂。
结构体类型的值一般由复合字面量来表达。
复合字面量可以由类型字面量和花括号包裹的键值对列表组成。
这里,键就是结构体类型中某个字段的名称,而值(又称元素)就是要赋给该字段的那个值。
表示结构体值的复合字面量可以简称为结构体字面量。
在同一个结构体字面量中,一个字段名称只能出现一次。
字段名必须唯一,可用"_"补位,支持使用自身指针类型成员.
字段名,排列顺序属于类型组成部分.除对齐处理外,编译器不会优化和调整内存布局。
package main
import "fmt"
type node struct {
_ int //没给值会使用默认值
id int
next *node
}
func main() {
n1 := node{
id: 1,
}
n2 := node{
id: 2,
next: &n1,
}
fmt.Println(n1, n2) //{0 1 <nil>} {0 2 0xc000048400}
}
可按顺序初始化全部字段,或使用命名方式初始化指定字段。
package main
import "fmt"
func main() {
type user struct {
name string
age int
}
u1 := user{"Tom", 12} //如果顺序初始化字段,就必须赋值全部字段
u2 := user{"Kebi"} //too few values in user literal,字段数量不够
u3 := user{ //命名初始化
name: "maoixan",
age: 18,
}
fmt.Println(u1, u3)
}
推荐使用命名初始化,这样在扩充结构字段或调整字段顺序时,不会导致语句初始化错误.
可以直接匿名结构类型变量,还可以将结构体用作字段类型。
package main
import "fmt"
func main() {
u := struct { //直接定义匿名结构变量
name string
age int8
}{
name: "kebi",
age: 18,
}
type file struct {
name string
attr struct { //定义匿名结构类型字段
owner int
perm int
}
}
f := file{
name: "test.py",
// attr: { //missing type in composite literal,对于结构体中的结构体赋值方式有所不同
// owner: 10,
// perm: 755,
// },
}
f.attr.owner = 10 //正确方式
f.attr.perm = 755
fmt.Println(u, f) //{kebi 18} {test.py {10 755}}
}
只有在所有字段类型全部支持时,才可做相等操作。
package main
import "fmt"
func main() {
type data struct {
x int
y map[string]int //字典类型不支持==,
}
d1 := data{
x: 100,
}
d2 := data{
x: 100,
}
fmt.Println(d1 == d2) //struct containing map[string]int cannot be compared
}
可使用指针直接操作结构字段,但不能是多级指针。
package main
import "fmt"
func main() {
type user struct {
name string
age int
}
p := &user{ //获取指针
name: "kebi",
age: 26,
}
p.name = "maoxian" //通过指针找到对应的程序实体
p.age++
fmt.Println(p) //&{maoxian 27}
p2 := &p //&p属于二级指针
*p2.name = "xiaoniao" //p2.name undefined (type **user has no field or method name)
}
空结构
空结构struct{}是指没有字段的结构类型。
它比较特殊,因为无论是其自身,还是作为数组元素类型,其长度都为0。
package main import (
"fmt"
"unsafe"
) func main() {
var a struct{} //匿名结构体
var b [100]struct{} //以结构体作为元素类型的数组 fmt.Println(unsafe.Sizeof(a), unsafe.Sizeof(b)) //0 0 s := b[:]
b[1] = struct{}{} //重新赋值
s[2] = struct{}{}
fmt.Println(s[3], len(s), cap(s)) //{} 100 100
}
实际上,这类长度为0的对象通常指向runtime.zerobase变量。
package main
import "fmt"
func main() {
a := [10]struct{}{}
b := a[:]
c := [0]int{}
fmt.Printf("%p, %p, %p\n", &a[0], &b[0], &c) //0x5771c8, 0x5771c8, 0x5771c8
}
空结构可作为通道元素类型,用于事件通知。
package main
import "fmt"
func main() {
exit := make(chan struct{})
go func() {
fmt.Println("hello, world!")
exit <- struct{}{}
}()
<-exit
fmt.Println("end.")
}
匿名字段
所谓匿名字段是指没有名字,仅有类型的字段,也称作嵌入字段或嵌入类型。
从编译器角度看,这只是隐式地以类型名作为字段名称。
可直接引用匿名字段的成员,但初始化时必须当作独立字段。
package main
import "fmt"
type attr struct {
perm int
}
type file struct {
name string
attr //仅有类型名
}
func main() {
f := file{
name: "test.dat",
attr: attr{ //将类型名当作字段名
perm: 755,
},
}
f.perm = 500 //直接设置匿名字段成员
fmt.Println(f, f.perm) //直接读取匿名字段成员
}
如果嵌入其它包中的类型,则隐式字段名称不包括包名。
不仅仅是结构体,除接口指针和多级指针以外的任何命名类型都可以作为匿名字段。
package main
import "fmt"
type data struct {
*int //嵌入指针类型
string
}
func main() {
x := 100
d := data{
int: &x, //使用基础类型作为字段名
string: "abc",
}
fmt.Printf("%#v\n", d)
}
/*
main.data{
int:(*int)(0xc00000a168),
string:"abc"
}
*/
不能将基础类型和其指针类型同时嵌入,因为两者隐式名字相同,下面就是错误示例。
// type data struct {
// *int
// int
// }
虽然可以像普通字段那样访问匿名字段成员,但会存在重名问题。
默认情况下,编译器从当前显式命名开始,逐步向内查找匿名字段成员。
如果匿名字段成员被外层同名字段遮蔽,那么必须使用显式字段名。
package main
import "fmt"
type file struct {
name string
}
type data struct {
file
name string //与匿名字段file.name重名
}
func main() {
d := data{
name: "data",
file: file{"file"}, //这种方式赋值并没有影响
}
fmt.Println(d.name, d.file.name) //data file
d.name = "data2"
d.file.name = "file2"
fmt.Println(d.name, d.file.name) //data2 file2
}
如果多个相同层级的匿名字段成员重名,就只能使用显式字段名访问,因为编译器无法确定目标。
package main
import "fmt"
type file struct {
name string
}
type log struct {
name string
}
type data struct {
file //file和log层次相同
log //file.name和log.name重名
}
func main() {
d := data{
file: file{"1.txt"},
log: log{"test.log"},
}
fmt.Println(d) //{{1.txt} {test.log}}
d2 := data{}
// d2.name = "name" //ambiguous selector d2.name
d2.file.name = "file" //显式命名字段
d2.log.name = "log"
fmt.Println(d2) //{{file} {log}}
}
严格说来,Go并不是传统意义上的面向对象编程语言,或者说仅实现了最小面向对象的机制。
匿名嵌入不是继承,无法实现多态处理。
虽然配合方法集,可用接口来显现一些类似的操作,但其本质完全不同。
字段标签
字段标签(tag)并不是注释,而是用来对字段进行描述的元数据。
尽管它不属于数据成员,但却是类型的组成部分。
在运行期,可以反射获取标签信息。常被用作格式校验,数据库关系映射等。
package main import (
"fmt"
"reflect"
) type user struct {
name string `昵称`
sex int `性别`
} func main() {
u := user{"Tom", 1}
v := reflect.ValueOf(u)
t := v.Type() for i, n := 0, t.NumField(); i < n; i++ {
fmt.Printf("%s: %v\n", t.Field(i).Tag, v.Field(i))
}
} /*
昵称: Tom
性别: 1
*/
go——结构的更多相关文章
- 【.net 深呼吸】细说CodeDom(1):结构大观
CodeDom 是啥东东?Html Dom听过吧,XML Dom听过吧.DOM一般可翻译为 文档对象模型,那 Code + DOM呢,自然是指代码文档模型了.如果你从来没接触过 CodeDom,你大概 ...
- 读书笔记:《HTML5开发手册》--HTML5新的结构元素
读书笔记:<HTML5开发手册> (HTML5 Developer's CookBook) 虽然从事前端开发已有很长一段时间,对HTML5标签也有使用,但在语义化上面理解还不够清晰.之前在 ...
- Python学习--04条件控制与循环结构
Python学习--04条件控制与循环结构 条件控制 在Python程序中,用if语句实现条件控制. 语法格式: if <条件判断1>: <执行1> elif <条件判断 ...
- HTML5 语义元素(一)页面结构
本篇主要介绍HTML5增加的语义元素中关于页面结构方面的,包含: <article>.<aside>.<figure>.<figcaption>.< ...
- React在开发中的常用结构以及功能详解
一.React什么算法,什么虚拟DOM,什么核心内容网上一大堆,请自行google. 但是能把算法说清楚,虚拟DOM说清楚的聊聊无几.对开发又没卵用,还不如来点干货看看咋用. 二.结构如下: impo ...
- ElasticSearch 5学习(10)——结构化查询(包括新特性)
之前我们所有的查询都属于命令行查询,但是不利于复杂的查询,而且一般在项目开发中不使用命令行查询方式,只有在调试测试时使用简单命令行查询,但是,如果想要善用搜索,我们必须使用请求体查询(request ...
- ASP.NET Core应用针对静态文件请求的处理[4]: DirectoryBrowserMiddleware中间件如何呈现目录结构
和StaticFileMiddleware中间件一样,DirectoryBrowserMiddleware中间本质上还是定义了一个请求地址与某个物理目录之间的映射关系,而目标目录体现为一个FilePr ...
- Go结构体实现类似成员函数机制
Go语言结构体成员能否是函数,从而实现类似类的成员函数的机制呢?答案是肯定的. package main import "fmt" type stru struct { testf ...
- CRL快速开发框架系列教程十(导出对象结构)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- Javacript实现字典结构
字典是一种用[键,值]形式存储元素的数据结构.也称作映射,ECMAScript6中,原生用Map实现了字典结构. 下面代码是尝试用JS的Object对象来模拟实现一个字典结构. <script& ...
随机推荐
- Linux高频指令总结
作为一个计算机专业的科班,不会玩Linux怎么能行呢?玩Linux用可视化界面显得太low了,为了效(zhuang)率(bi),当然要用什么都用指令啊,可是指令太多了啊,现在就把平时遇到的高频的指令做 ...
- 用Vue.js开发一个电影App的前端界面
我们要构建一个什么样的App? 我们大多数人使用在线流媒体服务(如Netflix)观看我们最喜欢的电影或者节目.这篇文章将重点介绍如何通过使用vue.js 2 建立一个类似风格的电影流媒体WEB交互界 ...
- Colored Sticks - poj2513(trie + 并查集)
问题便转化为:给定一个图,是否存在“一笔画”经过涂中每一点,以及经过每一边一次.这样就是求图中是否存在欧拉路Euler-Path.由图论知识可以知道,无向图存在欧拉路的充要条件为:① 图是连通的:② ...
- dva学习---effects异步中通过select获取当前的state
根据 在组件中dispatch一个action的例子中,如果要在effects中对于param数据和当前的state数据进行再出处理,这里怎么获取state呢?采用select,如下: e ...
- 自己编写Android Studio插件 别停留在用的程度了(转载)
转自:自己编写Android Studio插件 别停留在用的程度了 1概述 相信大家在使用Android Studio的时候,或多或少的会使用一些插件,适当的配合插件可以帮助我们提升一定的开发效率,更 ...
- 第二百三十四节,Bootstrap表单和图片
Bootstrap表单和图片 学习要点: 1.表单 2.图片 本节课我们主要学习一下 Bootstrap 表单和图片功能,通过内置的 CSS 定义,显示各 种丰富的效果. 一.表单 Bootstrap ...
- 抽象窗口工具包AWT (Abstract Window Toolkit) 是 API为Java 程序提供的建立 图形用户界面
抽象窗口工具包AWT (Abstract Window Toolkit) 是 API为Java 程序提供的建立 图形用户界面GUI (Graphics User Interface)工具集,AWT可用 ...
- 数码相机常用CCD/CMOS尺寸对比
数码相机的关键元件CCD或CMOS又称为“影像传感器”,其作用相当于感光胶片.CCD尺寸越大,采集光线的效果越好,画面记录的信息就越多,保留的细节也就越丰富,所以图像更完美漂亮. CCD尺寸的大小与像 ...
- ReactJS组件之间通信
http://www.open-open.com/lib/view/open1473838243065.html
- hdu5861(Road)
题目链接:传送门 题目大意:有n个点 组成n-1段,每一段开着的时候都有花费Vi,有m组要求,对于每组要求 [x,y]之间可达,对于每一段你有一次开关的机会(最初都是关闭的) 问怎样安排段落得开闭时间 ...