Maps

什么是 map ?

  类似Python中的字典数据类型,以k:v键值对的形式。

  map 是在 Go 中将值(value)与键(key)关联的内置类型。通过相应的键可以获取到值。

如何创建 map ?

  通过向 make 函数传入键和值的类型,可以创建 map。make(map[type of key]type of value) 是创建 map 的语法。

// personSalary := make(map[string]int)

  上面的代码创建了一个名为 personSalary 的 map,其中键是 string 类型,而值是 int 类型。

map 的零值是 nil。如果你想添加元素到 nil map 中,会触发运行时 panic。因此 map 必须使用 make 函数初始化。

//maps
package main import "fmt" func main() {
//maps的定义
//map的key值必须可hash
//var a map[键值类型]value值类型
//map的空值是nil类型
var a map[int]string
fmt.Println(a)
if a==nil{
fmt.Println("xxxx")
}
}

map修改和添加元素

  给 map 添加新元素的语法和数组相同

package main
import "fmt"
func main(){ //map的赋值跟取值
//map的初始化
var a map[int]string=make(map[int]string)
fmt.Println(a)
if a==nil{
fmt.Println("hello")
} a[1]="100"
a[2]="888"
fmt.Println(a)
fmt.Println(a[1]) ////取一个不存在的key值会?返回value值的空值
  ////fmt.Println(a[9])
//var b map[int]int=make(map[int]int)
//b[1]=100
//fmt.Println(b)
////fmt.Println(b[9])
//if v,ok:=a[9];ok{
// fmt.Println("=-====",v)
//}else {
// fmt.Println("该值不存在")
//}
//v,ok:=a[1]
//fmt.Println(v)
//fmt.Println(ok) //定义和初始化的第二种方式
//var a =map[int]string{1:"10",2:"100"}
////a[1]
//fmt.Println(a[1])
}

对应的以key:value的形式赋值,赋值和取值都是通过key来操作value的。

删除 map 中的元素

  删除 map 中 key 的语法是 [delete(map, key)]。这个函数没有返回值。

package main

import (
"fmt"
) func main() {
personSalary := map[string]int{
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
fmt.Println("map before deletion", personSalary)
delete(personSalary, "steve")
fmt.Println("map after deletion", personSalary) }

上述程序删除了键 "steve",输出:

map before deletion map[steve:12000 jamie:15000 mike:9000]
map after deletion map[mike:9000 jamie:15000]

获取 map 的长度

  获取 map 的长度使用 [len]函数。

package main

import (
"fmt"
) func main() {
personSalary := map[string]int{
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
fmt.Println("length is", len(personSalary)) }

上述程序中的 len(personSalary) 函数获取了 map 的长度。程序输出 length is 3。3对k:v键值对。

Map 是引用类型

  和 [slices]类似,map 也是引用类型。当 map 被赋值为一个新变量的时候,它们指向同一个内部数据结构。因此,改变其中一个变量,就会影响到另一变量。

package main
import "fmt"
func main(){
//Map 是引用类型
var a =map[int]string{1:"10",2:"100"}
test4(a)
fmt.Println(a)
func test4(a map[int]string) {
a[1]="888"
fmt.Println(a) }

当 map 作为函数参数传递时也会发生同样的情况。函数中对 map 的任何修改,对于外部的调用都是可见的。

Map 的相等性

  map 之间不能使用 == 操作符判断,== 只能用来检查 map 是否为 nil

package main
import "fmt"
func main(){ //Map 的相等性
map1 := map[string]int{
"one": 1,
"two": 2,
} map2 := map1 if map1 == map2 { //报错
} //map循环出所有元素
//var a =map[int]string{1:"10",0:"100",10:"999"}
////for i:=0;i<len(a);i++{
//// fmt.Println(a[i])
////}
////map是无序的
//for k,v:=range a{
// fmt.Println(k)
// fmt.Println(v)
//} //补充:切片删除元素
//var a =[]int{1,2,3,4,5,6}
//a=append(a[0:2],a[3:]...)
//fmt.Println(a)
} }

上面程序抛出编译错误 invalid operation: map1 == map2 (map can only be compared to nil)

判断两个 map 是否相等的方法是遍历比较两个 map 中的每个元素。我建议你写一段这样的程序实现这个功能

字符串

什么是字符串?

  Go 语言中的字符串是一个字节切片。把内容放在双引号" "之间,我们可以创建一个字符串。让我们来看一个创建并打印字符串的简单示例。

package main

import (
"fmt"
) func main() {
name := "Hello World"
fmt.Println(name)
}

上面的程序将会输出 Hello World

Go 中的字符串是兼容 Unicode 编码的,并且使用 UTF-8 进行编码。

其他方法:

package main
import (
"fmt"
"unicode/utf8"
)
package main import (
"fmt"
"unicode/utf8"
)
func main() { name := "Hello World蟒蛇"
//name:="赵"
//字符串长度,len统计字节数
//在go种string类型都是utf-8编码 fmt.Println(len(name))
fmt.Println(utf8.RuneCountInString(name))
//unicode是一个字符编码对照表 //循环
//字符串是个只读切片
//name := "name赵"
//for i:=0;i<len(name);i++{
// fmt.Println(string(name[i]))
// fmt.Printf("%T",name[i])
// fmt.Println()
//} //for _,v:=range name{
// fmt.Println(string(v))
// fmt.Printf("%T",v)
// fmt.Println()
//} //name := "name赵"
//name[0]=99
//fmt.Println(name[0])
//fmt.Println(string(name[0])) byteSlice := []byte{0x43, 0x61, 0x66, 0xC3, 0xA9}// 打印的是字节数
str := string(byteSlice)
a:=len(str)
b:=utf8.RuneCountInString(str)
fmt.Println(b)
fmt.Println(a)
fmt.Println(str)
}

需要注意的是:字节数和字符数的区别,一个字节占用了三个字符个数;取长度的关键字:-len(str)    utf8.RuneCountInString(str)

单独获取字符串的每一个字节

  由于字符串是一个字节切片,所以我们可以获取字符串的每一个字节。

package main

import (
"fmt"
) func printBytes(s string) {
for i:= 0; i < len(s); i++ {
fmt.Printf("%x ", s[i])
}
} func main() {
name := "Hello World"
printBytes(name)
}

go中的string字符串的形式都是以utf-8的形式存入内存中,而其他语言以Unicode万国码形式,获取长度用:

字符串的 for range 循环

  循环出来的是一个个的字符数,可以用rune的方法和for range的方法

package main
import "fmt"
func main(){ //循环
//字符串是个只读切片
// 第一种:循环字节的个数
name := "name赵"
//for i:=0;i<len(name);i++{
// fmt.Println(string(name[i]))
// fmt.Printf("%T",name[i])
// //fmt.Println()
//}
// 循环出来的字符的个数,一般用第二种,会乱码
for _,v:=range name{
fmt.Println(string(v)) //转格式
fmt.Printf("%T",v)
fmt.Println()
}
//字符串是个只读切片,只能读,不能等修改
//name := "name赵"
//name[0]=99
fmt.Println(name[0])
fmt.Println(string(name[0])) }

字符串是不可变的,Go 中的字符串是不可变的。一旦一个字符串被创建,那么它将无法被修改

字符只能读取,不支持修改。

用字节切片构造字符串

package main

import (
"fmt"
"unicode/utf8"
)
func main() {
byteSlice := []byte{0x43, 0x61, 0x66, 0xC3, 0xA9}// 打印的是字节数
str := string(byteSlice)
a:=len(str)
b:=utf8.RuneCountInString(str)
fmt.Println(b)
fmt.Println(a)
fmt.Println(str)
}

指针

什么是指针?

  指针是一种存储变量内存地址(Memory Address)的变量。

如上图所示,变量 b 的值为 156,而 b 的内存地址为 0x1040a124。变量 a 存储了 b 的地址。我们就称 a 指向了 b

指针的声明

指针变量的类型为 *T,该指针指向一个 T 类型的变量。

总结:

 //&取地址符号
//* 放在类型旁边,表示指向这个类型的指针
//* 放在变量旁边,表示解引用(反解)

例子:

//指针
package main import "fmt"
func main() {
//&取地址符号
//* 放在类型旁边,表示指向这个类型的指针
//* 放在变量旁边,表示解引用(反解)
a:=10
//b就是一个指针 指向int类型的指针
//b:=&a
//d:="sss"
//var c *string=&d
var b *int =&a
fmt.Println(b)
fmt.Println(*b) //把b对应的值给取出来
c:=&b
//var c **int=&b //指向int类型的指针
fmt.Println(*(*c))
}

指针的零值(Zero Value)

指针的零值是 nil

package main
import "fmt"
func main(){
//指针的零值(Zero Value),nil类型
//var a *int
//fmt.Println(a)
}>>>nil

向函数传递指针参数

package main

import "fmt"

func change(val *int)  {
*val = 55
}
func main() {
a:=58
fmt.Println(a)
b:=&a
change(b)
fmt.Println(a)
}

在上面程序中的,我们向函数 change 传递了指针变量 b,而 b 存储了 a 的地址。程序在 change 函数内使用解引用。

不要向函数传递数组的指针,而应该使用切片

  假如我们想要在函数内修改一个数组,并希望调用函数的地方也能得到修改后的数组,一种解决方案是把一个指向数组的指针传递给这个函数。

    //向函数传递指针参数
a := 10
b := &a
test6(b)
fmt.Println(a)
test7(a)
fmt.Println(a) //不要向函数传递数组的指针,而应该使用切片
var a [100]int
test9(&a)
fmt.Println(a)
test10(a[:])
fmt.Println(a)
//Go 不支持指针运算 func test9(a *[4]int) {
(*a)[0]=999
fmt.Println(a)
}
func test10(a []int) {
a[0]=999
fmt.Println(a) }

只是不建议,可以使用,但系统默认会认为是指针的地址。

Go 不支持指针运算

  Go 并不支持其他语言(例如 C)中的指针运算。

package main

func main() {
b := [...]int{109, 110, 111}
p := &b
p++
}

上面的程序会抛出编译错误:main.go:6: invalid operation: p++ (non-numeric type *[3]int)

16. 结构体

什么是结构体?

  类似其他语言的面向对象,一个类有属性有方法;go中可以通过其他的方法实现类的三大属性:继承,封装,多态派生的方法。

  结构体是用户定义的类型,表示若干个字段(Field)的集合。有时应该把数据整合在一起,而不是让这些数据没有联系。这种情况下可以使用结构体。

例如,一个职员有 firstNamelastName 和 age 三个属性,而把这些属性组合在一个结构体 employee 中就很合理。

结构体的声明

格式:type 关键字 解构体名字 struct{ }

package main

import "fmt"

//结构体:是一系列属性的集合
//定义一个人结构体
//type关键字 结构体名字 struct{}
type Person struct {
name string
sex int
age int } func main() {
//person :=Person{}
//定义没有初始化
//结构体是值类型
//var person Person
//var person Person=Person{name:"lqz"}
var person Person=Person{"lqz",1,19}
//person.name="lqz"
fmt.Println(person.name) // 获取的话直接·属性
}

创建匿名结构体

  匿名就是没有type的结构体名,但要引用的话必须先实例化才能使用,与一般的结构体有点区别而已。

package main
import "fmt"
func main(){
a:=struct {
name string
age int
hobby string
}{"rose",19,"music"}
fmt.Printf(a.name)
//fmt.Printf(a.age)
fmt.Printf( a.hobby) }

结构体的零值(Zero Value)

  当定义好的结构体并没有被显式地初始化时,该结构体的字段将默认赋为零值,有字段决定。

package main

import (
"fmt"
) type Employee struct {
firstName, lastName string
age, salary int
} func main() {
var emp4 Employee //zero valued structure
fmt.Println("Employee 4", emp4)
}

该程序定义了 emp4,却没有初始化任何值。因此 firstName 和 lastName 赋值为 string 的零值("")。

而 age 和 salary 赋值为 int 的零值(0)。该程序会输出:

 
Employee 4 { 0 0}

结构体的指针

  也可以创建指向结构体的指针。

package main
import "fmt"
func main(){
//结构体指针
p:=Person{name:"lqz"}
//pPoint:=&p
var pPoint *Person=&p
//fmt.Println(pPoint)
//fmt.Println((*pPoint).name)
fmt.Println(pPoint.name) }

匿名字段

  当我们创建结构体时,字段可以只有类型,而没有字段名。这样的字段称为匿名字段

以下代码创建一个 Person 结构体,它含有两个匿名字段 string 和 int

type Person struct {
string
int
}

我们接下来使用匿名字段来编写一个程序。

package main

import (
"fmt"
) type Person struct {
string
int
} func main() {
p := Person{"Naveen", 50}
fmt.Println(p)
}

  上述直接传相应的字段类型的值即可,会自动匹配字段类型。

虽然匿名字段没有名称,但其实匿名字段的名称就默认为它的类型

嵌套结构体(Nested Structs)

  字段定义的时候,字段里嵌套另一个字段。

// 嵌套结构体
package main
import "fmt" type Person struct{
  name string
  sex int
  age int
  hobby Hobby } type Hobby struct{
  id int
  name string } func main(){ //erson{name:"gai",hobby:Hobby{id:10,name:"篮球“} // 两种传参方式
p:=Person{name:"lqz",hobby:Hobby{id:10,name:"篮球"}}
p.hobby.id=102 fmt.PrintLn(P.hobby.name) // 获取属性值的方法
} }
//变量提升过程中如果有重名的,就不提升了
//p:=Person{name:"lqz",Hobby:Hobby{10,"篮球"}}
//fmt.Println(p.Hobby.name)
//fmt.Println(p.name)
>>:篮球

提升字段(Promoted Fields)

有点类似面向对象的继承,继承类中的属性。

  如果是结构体中有匿名的结构体类型字段,则该匿名结构体里的字段就称为提升字段。这是因为提升字段就像是属于外部结构体一样,可以用外部结构体直接访问。

type Address struct {
city, state string
}
type Person struct {
name string
age int
Address
}

  在上面的代码片段中,Person 结构体有一个匿名字段 Address,而 Address 是一个结构体。

现在结构体 Address 有 city 和 state 两个字段,访问这两个字段就像在 Person 里直接声明的一样,因此我们称之为提升字段。

package main

import (
"fmt"
) type Address struct {
city, state string
}
type Person struct {
name string
age int
Address
} func main() {
var p Person
p.name = "Naveen"
p.age = 50
p.Address = Address{
city: "Chicago",
state: "Illinois",
}
fmt.Println("Name:", p.name)
fmt.Println("Age:", p.age)
fmt.Println("City:", p.city) //city is promoted field
fmt.Println("State:", p.state) //state is promoted field
}

在上面代码中的第 26 行和第 27 行,我们使用了语法 p.city 和 p.state,访问提升字段 city 和 state 就像它们是在结构体 p 中声明的一样。该程序会输出:

 
Name: Naveen
Age: 50
City: Chicago
State: Illinois

结构体相等性(Structs Equality)

  结构体是值类型。如果它的每一个字段都是可比较的,则该结构体也是可比较的。如果两个结构体变量的对应字段相等,则这两个变量也是相等的

练习:

通过map为数组添加三个元素,执行代码map[0](9)得到9,map[1](9得到81,mapp[2](9)得到729.

//-map内放函数
//-通过map实现set func main() {
var m map[int]func(a int)int=make(map[int]func(a int)int)
m[1]= func(a int) int { return a
}
m[2]= func(a int) int {
return a*a
}
m[3]= func(a int) int {
return a*a*a
} fmt.Println(m[1](9))
fmt.Println(m[2](9))
fmt.Println(m[3](9))
}

 

map 实现set类型,增加删除修改元素,判断元素是否存在,获取len 等

func main() {
//集合
//可以放值,如果重复了,放不进去
//可以获取长度
//判断一个值是否在集合内
//把集合内所有元素打印出来 var m map[string]bool=make(map[string]bool)
m["lqz"]=true
m["egon"]=true m["lqz"]=true fmt.Println(len(m))
//"aa"是否在集合内
if m["aa"]{
fmt.Println("在里面")
}else {
fmt.Println("不再")
}
for k,_:=range m{
fmt.Println(k)
} }
 
												

Go-map-字符串-指针-结构体的更多相关文章

  1. Go-常识补充-切片-map(类似字典)-字符串-指针-结构体

    目录 Go 常识补充 Go 命名 打印变量类型科普 _ 关键字 命名规范相关 包目录规范 切片 多维切片 切片初始化的方法 多维切片初始化 切片删除元素(会略微影响效率 ,少用) copy 函数 打散 ...

  2. 【AT91SAM3S】SAM3S-EK Demo工程中,LCD驱动程序的加载(函数指针结构体)

    为了调试LCD,在英倍特的板子上烧Atmel的sam3s-ek_demo_1.4_source示例代码.LCD显示正常了,却找不到LCD的驱动究竟在哪. 花了好久,追踪到了这个执行过程. 进入main ...

  3. C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com

    原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | I ...

  4. C学习笔记(5)--- 指针第二部分,字符串,结构体。

    1. 函数指针(function pointer): 函数指针是指向函数的指针变量. 通常我们说的指针变量是指向一个整型.字符型或数组等变量,而函数指针是指向函数. 函数指针可以像一般函数一样,用于调 ...

  5. go 学习 (三):函数 & 指针 & 结构体

    一.函数 函数声明 // 声明语法 func funcName (paramName paramType, ...) (returnType, returnType...) { // do somet ...

  6. 深入理解指针—>结构体里的成员数组和指针

    单看这文章的标题,你可能会觉得好像没什么意思.你先别下这个结论,相信这篇文章会对你理解C语言有帮助.这篇文章产生的背景是在微博上,看到@Laruence同学出了一个关于C语言的题,微博链接.微博截图如 ...

  7. typedef struct 指针结构体使用方法

    A>>>>>>>>>>>>>>>>>>>>>>>> ty ...

  8. 【C++】结构体/结构体数组/结构体指针/结构体嵌套/函数参数/const

    一.结构体声明 struct Student { //成员列表 string name; int age; int score; }; //s3;定义时直接声明 int main() { struct ...

  9. Hihocoder #1014 : Trie树 (字典数树统计前缀的出现次数 *【模板】 基于指针结构体实现 )

    #1014 : Trie树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助, ...

随机推荐

  1. Unity UGUI优化整理

    看了不少UI优化方面的东西,还是记下来方便记忆,优化性能往往是在各种选择之间做出平衡(空间换时间,或者GPU换CPU,舍弃精度等). 主要优化点在减少Drawcall,减少Overdraw. Mask ...

  2. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:测试SSH框架分层整合及验证事务是否有效

    测试框架分层的整合 HibernateTemplate 和 HibernateDaoSupport,这两个类是 Spring 为整合 Hibernate3 提供的两个工具类. HibernateTem ...

  3. spring boot 连接Mysql介绍

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

  4. css 基础知识 (待完善...)

    CSS   1.position 属性     对元素进行定位.       absolute         相对于 非static类型的position 的 第一个(临近的) 父元素 进行定位. ...

  5. CSU-ACM2020寒假集训比赛2

    A - Messenger Simulator CodeForces - 1288E 两种解法,我选择了第二种 mn很好求,联系过就是1,没联系过就是初始位置 第一种:统计同一个人两次联系之间的出现的 ...

  6. Pickle incompatibility of numpy arrays between Python 2 and 3

    Traceback (most recent call last): File "mnist.py", line 7, in <module> train_set, v ...

  7. Swift - UISplitViewController

    https://blog.csdn.net/weixin_43704791/article/details/86424080 2019年01月13日 AppDelegate中: func applic ...

  8. 渗透测试 - HPP数据污染 - 原理 | 场景

    Web服务器 参数获取函数    获取到的参数 PHP/Apache   $_GET(“par”)  Last JSP/Tomcat   Request.getParameter(“par”)    ...

  9. unzip 小坑

    unzip test.zip 直接将zip解压到当前目录下,保留test级目录. unzip test.war 直接将.war解压到当前目录,不保留test级目录,所以建议使用 unzip test. ...

  10. Q8:String to Integer (atoi)

    8. String to Integer (atoi) 官方的链接:8. String to Integer (atoi) Description : Implement atoi to conver ...