ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

golang学习随便记4

2021-09-12 17:29:49  阅读:198  来源: 互联网

标签:随便 string Point int golang map Circle main 学习


复合数据类型(构造类型)

map

golang map 是Hash表的引用,差不多就是PHP 关联数组或者 Python 字典,当然 C++ STL 也有map,但 golang map 应该是 unordered_map。map 所有键必须同类型,值也必须同类型,这一点并不像 PHP 关联数组那样随心所欲,另外,键必须是支持 == 进行比较的,所以通常它是一个原始基本类型。由于浮点比较的不精确性,所以用浮点数为键不是好主意(golang NaN可以是浮点)。

初始化一个map,类似如下:

ages := map[string]int {
    "Alice":   31,
    "Charlie": 34,
}

创建一个空的map,有两种方式

ages := map[string]int {}
// or
ages := make(map[string]int)

移除map的某个元素(键值对),可以使用内置函数 delete,如

delete(ages, "Alice")

可以安全地删除不存在的元素(键不存在),甚至可以安全地访问不存在的键(此时返回该类型的零值)或者修改它(此时先自动创建元素再修改),例如

ages["Bob"] = ages["Bob"] + 1
// or
ages["Bob"] += 1
// or
ages["Bob"]++

上面的代码,都会先主动创建键为Bob,值为0的元素,然后将值加1,这一点似乎比STL map要更夸张一点。

golang map的键是无序的,这和 STL map 用红黑树内部有序不同,如果确实需要按键排序,只能遍历map把键取出作为一个数组,对该数组排序再来索引map。

map 的元素访问,遍历都是自然的,只是不存在的键也可以访问(返回零值)。那么如何区分返回的恰好是0,还是因为键不存在返回了0?答案是访问键不仅返回值,还可以同时返回检索是否成功:

age, ok := ages["bob"]
if !ok { /* not key! */ }
// or
if age, ok := ages["bob"]; !ok { /* not key! */ }

和 slice 一样,除了用 == 或 != 和 nil 作比较,map 是不可比较的。确实要比较2个map,只能手动自己写函数,只是 map 允许访问不存在的键,给比较函数带来一个小坑

package main

import (
	"fmt"
)

func main() {
	map1 := map[string]int{"A": 0}
	map2 := map[string]int{"B": 42}
	fmt.Println(equal(map1, map2))		// false
}

func equal(x, y map[string]int) bool {
	if len(x) != len(y) {
		return false
	}
	for k, xv := range x {
		if yv, ok := y[k]; !ok || yv != xv { // y 中键 k 不存在也是不等的
			return false
		}
	}
	return true
}

golang 没有集合类型,但可以直接用 map[T]bool 来代替集合。当我们希望键是某种不可比较的类型(例如 slice)时怎么办?和前面的排序问题一样,变通实现,即引入辅助函数k(),确保当且仅当 x 和 y 相等时, k(x) == k(y),而且 k() 返回类型是可以比较的(通常是字符串类型),然后创建 map[k(T)]T‘形式的map

map 的值类型可以是复合类型,如 slice 或者又一个map,make(map[string]map[string]bool) 将创建键为string,值为map类型,值的map类型中的键为string,值为bool

结构体

golang结构体和C结构体比较相似,不过golang结构体成员可以是空的,另外,声明的时候是用定义新类型(类型别名)的方式进行的:

type Employee struct {
	ID			int
	Name		string
	Address		string
	DoB			time.Time
	Position	string
	Salary		int
	ManagerID	int
}

用该类型声明变量 var  john Empoyee

访问成员 john.Salary -= 5000

指针访问 position := &john.Position;   *position = "Senior " + *position

指向结构体的指针也用点号.访问!

var  e  *Empoyee = &john  ;    e.Position += "  (proactive team player)"

结构体成员的名字和顺序很重要,在不改变顺序情况下,相同类型的成员可以简化写成一行。

golang 结构体有一个被王垠大神吐槽的访问控制机制,即成员变量名称首字母大写意味着该变量是可导出的,而小写的是私有的。这个和包全局变量的情况一致。

结构体初始化可以使用两种方式(短结构多用方式一,复杂结构多用方式二),但不能混用

package main

import (
	"fmt"
)

func main() {
	p1 := Point{1, 2}		// 方式一
	p2 := Point{Y: 2, X: 1}	// 方式二,可不按顺序
	p3 := Point{X: 1}		// 方式二,部分成员给定值,其余默认0值
	fmt.Println(p1)			// {1 2}
	fmt.Println(p2)			// {1 2}
	fmt.Println(p3)			// {1 0}
}

type Point struct {
	X, Y int
}

结构体类型作为函数参数,也是拷贝的(值传递),所以,对于大的结构体作为函数参数,一般使用指针方式。创建、初始化结构体变量并获取它的地址可以一步完成: 

pp := &Point{1, 2}
// 等价于
pp := new(Point)
*pp = Point{1, 2}

&Point{1, 2} 一步完成(返回了指针),所以可以作为函数实参。

结构体是否可以用 == 或 != 比较,是由其所有成员决定的,即所有成员可以比较,结构体才可以比较。当结构体可以用 == 比较时,它可以作为map的键。

golang支持嵌套匿名结构体,并为访问匿名结构体的成员提供快捷语法:

package main

import (
	"fmt"
)

func main() {
	var w Wheel
	w.X = 8      // 等价于 w.Circle.Point.X = 8
	w.Y = 8      // 等价于 w.Circle.Point.Y = 8
	w.Radius = 5 // 等价于 w.Circle.Radius = 5
	w.Spokes = 20
	fmt.Println(w) // {{{8 8} 5} 20}
	w1 := Wheel{Circle{Point{8, 8}, 5}, 20}
	w2 := Wheel{
		Circle: Circle{
			Point:  Point{X: 8, Y: 8},
			Radius: 5,                // 这个逗号是必需的!
		},
		Spokes: 20,                   // 这个逗号是必需的!
	}
	fmt.Printf("%#v\n", w1)
	fmt.Printf("%#v\n", w2)
}

type Point struct {
	X, Y int
}

type Circle struct {
	Point  // 匿名结构体,自动嵌入成员 X, Y
	Radius int
}

type Wheel struct {
	Circle // 匿名结构体,自动嵌入 X, Y, Radius
	Spokes int
}

代码中,结构体用字面量初始化时,仍然只能用标准方式(注意代码中含嵌套的结构体初始化时最后一个成员尾部的逗号,可以理解为”有儿子的结构体初始化最后一个成员后加逗号“)。上述代码输出

{{{8 8} 5} 20}
main.Wheel{Circle:main.Circle{Point:main.Point{X:8, Y:8}, Radius:5}, Spokes:20}
main.Wheel{Circle:main.Circle{Point:main.Point{X:8, Y:8}, Radius:5}, Spokes:20}

对于嵌套结构体的成员的访问控制,例如 point 不可导出,但有可导出的成员 X 和 Y,当将它通过 circle(不可导出)嵌入 Wheel 时, w.X 在引入Wheel的包仍然可用,但 w.circle.point.X 就不行。简单理解,嵌入的成员它的访问控制并不由原来的结构体说了算,好像它已经成了包含嵌体的结构体的成员。

嵌入的匿名成员,并不限于结构体类型,任何命名的类型或指向命名类型的指针都可以。用快捷方式访问匿名成员的方式,不仅适用于匿名成员内部变量,也适用于它的方法。这种机制,帮助 golang 实现了 聚合方式的 OOP。

----

标签:随便,string,Point,int,golang,map,Circle,main,学习
来源: https://blog.csdn.net/sjg20010414/article/details/120250902

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有