• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Go-map-字符串-指针-结构体

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

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)

什么是结构体?

  类似其他语言的面向对象,一个类有属性有方法;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)
    }


}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
 
                    
            
                

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
利用基于GoLang的Hugo配合nginx来打造属于自己的纯静态博客系统 ...发布时间:2022-07-10
下一篇:
Go语言中定时器的使用发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap