golang-指针,函数,map

摘要:
当我们理解指针的之后,就可以通过指针的的方法来解决上面的这个问题,将代码更改为:packagemainimport"fmt"funcmodify{*num=1000}funcmain(){a:=1modify(&a)fmt.Println}内置函数len:用于求长度,比如string、array、slice、map、channelnew:来分配内存,主要来分配值类型,如int、struct。这里要特别注意new返回的是一个指针new函数也是创建变量的一种方式。
指针

普通类型变量存的就是值,也叫值类型。指针类型存的是地址,即指针的值是一个变量的地址。
一个指针只是值所保存的位置,不是所有的值都有地址,但是所有的变量都有。使用指针可以在无需知道
变量名字的情况下,间接读取或更新变量的值。

获取变量的地址,用&,例如:var a int 获取a的地址:&a,&a(a的地址)这个表达式获取一个指向整型变量的指针,它的类型是整形指针(*int),如果值叫做p,我们说p指向x,或者p包含x的地址,p指向的变量写成
*p ,而*p获取变量的值,这个时候*p就是一个变量,所以可以出现在赋值操作符的左边,用于更新变量的值

指针类型的零值是nil
两个指针当且仅当指向同一个变量或者两者都是nil的情况才相等

通过下面小例子进行理解指针:

package main
import "fmt"
func main() {
    x := 1
    //&x 获取的是变量x的地址,并赋值给p,这个时候p就是一个指针
    //p是指针,所以*p获取的就是变量的值,指针指向的是变量x的值,即*p为1
    p := &x
    fmt.Println(*p)
    //这里*p 进行赋值,也就是更改了变量x的值,即实现不知道变量的名字更改变量的值
    *p = 2
    fmt.Println(x)
}

再看一个关于通过一个函数来修改变量值的问题:

package main
import "fmt"
func modify(num int) {
    num = 1000
}
func main() {
    a := 1
    modify(a)
    fmt.Println(a)
}

这个例子是修改变量的值,但是最后打印变量a的值是还是10,所以这里就需要知道,当通过定义的函数modify来修改变量的值时,传入变量a其实会进行一次拷贝,传入的其实是a变量的一个副本,所以当通过
modify修改的时候修改的是副本的值,并没有修改变量a的值。
当我们理解指针的之后,就可以通过指针的的方法来解决上面的这个问题,将代码更改为:


package main
import "fmt"
func modify(num *int) {
    *num = 1000
}
func main() {
    a := 1
    modify(&a)
    fmt.Println(a)
}
内置函数

len: 用于求长度,比如string、array、slice、map、channel
new: 来分配内存,主要来分配值类型,如int、struct。返回的是指针
make: 来分配内存,主要 来分配引 类型, 如chan、map、slice
append: 来追加元素到数组、slice中
panic和recover: 来做错误(这个后续整理)

下面重点整理new和make

new函数

func new(Type) *Type
先看一下官网对这个内置函数的介绍:
内置函数 new 用来分配内存,它的第一个参数是一个类型,不是一个值,它的返回值是一个指向新分配类型零值的指针。这里要特别注意new返回的是一个指针

new函数也是创建变量的一种方式。表达式new(T)创建一个未命名的T类型变量,初始化T类型的零值,并返回其地址(地址类型为*T)

通过下面例子进行理解:

package main
import "fmt"
func newFunc() {
    p := new(int)
    fmt.Println(p)  //打印是地址
    fmt.Println(*p) //int类型的零值为0这里打印0
    *p = 2
    fmt.Println(*p) //*p已经为其地址指向了一个变量2,所以这里打印为2
}
func main() {
    newFunc()
}

这里我们要知道new创建的变量和取其地址的普通局部变量没有什么不同,只是语法上的便利

如果我们定义一个指针是不能直接给这个指针赋值的,而是需要先给这个指针分配内存,然后才能赋值
下面例子先不初始化分配内存,直接赋值会报错,如下:

package main
import "fmt"
//new创建变量的方式
func newIntFunc() *int{
    return new(int)
}
//取地址的普通局部变量
func newIntFunc2() *int{
    var res int
    return &res
}
func main() {
    var p1 *int
    /**
        注意下面这句p1 = newIntFunc()必须有,否则会报错
        <nil>
    panic: runtime error: invalid memory address or nil pointer dereference
    [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x108d723]
    goroutine 1 [running]:
    main.main()
            /Users/zhangjinyu/learngo/src/go_dev/day04/new1/new1.go:18 +0x63
    exit status 2
    */
    p1 =newIntFunc()
    fmt.Println(p1)
    *p1 = 22
    fmt.Println(*p1)
    var p2 *int
    p2 =newIntFunc2()
    fmt.Println(p2)
    *p2 = 33
    fmt.Println(*p2)
}

make函数

func make(Type, size IntegerType) Type
先看一下官网对这个内置函数的介绍:
内置函数make用来为slice,map或chan类型分配内存或初始化一个对象(这里需要注意:只能是这三种类型)
第一个参数也是一个类型而不是一个值
返回的是类型的引用而不是指针,而且返回值也依赖具体传入的类型
注意:make返回初始化后的(非零)值。

其实在上一篇整理切片slice的时候就用到了make如:
make([]type,len)
当时通过make来初始化slice的时候,第二个参数指定了它的长度,如果没有第三个参数,它的容量和长度相等,当然也可以传入第三个参数来指定不同的容量值,但是注意不能比长度值小

这里提前说一下通过make初始化map的时候,根据size大小来初始化分配内存,不过分配后的map长度为0,如果size被忽略了,会在初始化分配内存的时候分配一个小的内存

关于new和make的一个小结:
new 的作用是初始化一个指向类型的指针 (*T),make的作用是为slice,map或者channel初始化,并且返回引用 T

函数

函数的声明语法:func 函数名 (参数 表) [(返回值 表)] {}
这了要注意第一个花括号必须和func在一行

常见的几种声明函数的方法:
func add(){

}

func add(a int,b int){

}

func add(a int,b int) int{

}

func add(a int, b int)(int,int){

}

func add(a ,b int)(int,int){

}

golang函数的特点:

    1. 不支持重载,即一个包不能有两个名字一样的函数
    2. 函数也是一种类型,一个函数可以赋值给变量
    3. 匿名函数
    4. 多返回值

演示一些函数的例子:

package main
import (
    "fmt"
)
func add(a, b int) int{
    return a +b
}
func main() {
    c := add //这里把函数名赋值给变量c
    fmt.Printf("%p %T", c, add)
    sum := c(10, 20) //调用c其实就是在调用add
    fmt.Println(sum)
}

还有一个:

package main
import (
    "fmt"
)
type addFunc func(int, int) int
func add(a, b int) int{
    return a +b
}
func operator(op addFunc, a int, b int) int{
    return op(a, b)
}
func main() {
    c :=add
    sum := operator(c, 100, 200)
    fmt.Println(sum)
}

变量作用域

在函数外面的变量是全局变量
函数内部的变量是局部变量
go中变量的作用域有多种情况:
函数级别的,代码块级别的

关于函数的可变参数

变长函数被调用的时候可以有可变的参数个数
在参数列表最后的类型名称前使用省略号...可以声明一个变长的函数,
例如:
0个或多个参数
func add(arg...int) int{

}
1个或多个参数
func add(a int,arg...int) int{

}
2个或多个参数
func add(a int,b int,arg...int)int{

}

关于函数参数的传递

不管是值类型还是引用传递,传递给函数的都是变量的副本
注意:map,slice,chan,指针,interface默认以引用方式传递

延迟函数defer的调用

语法上,一个defer语句就是一个普通的函数或者方法调用,在调用之前加上关键字defer。函数和参数表达式会在语句执行时求值,但是无论是正常情况还是执行return语句或者函数执行完毕,以及不正常情况下,如程序发生宕机,实际的调用推迟到包含defer语句的函数结束后才执行,defer语句没有限制使用次数。

defer用途:

  1. 当函数返回时,执行defer语句,因此可以用来做资源清理
  2. 多个defer语句,按先进后出的方式执行
  3. defer语句中的变量,在defer声明时就决定了

先通过一个小例子理解defer:

package main
import (
    "fmt"
)
func testDefer(){
    a := 100
    fmt.Printf("before defer:a=%d
",a)
    defer fmt.Println(a)
    a = 200
    fmt.Printf("after defer:a=%d
",a)
}
func main(){
    testDefer()
}

这里我们可以这样理解当我们执行defer语句的时a=100,这个时候压入到栈中,等程序最后结束的时候才会调用defer语句,所以打印的顺序是最后才打印一个数字100

defer语句经常使用成对的操作,比如打开和关闭,连接和断开,加锁和解锁

下面拿关闭一个打开文件操作为例子,当我们通过os.Open()打开一个文件的时候可以在后面添加defer f.Close() 这样在函数结束时就可以帮我们自动关闭一个打开的文件

map类型

key-value的数据结构,又叫字典

声明
var map1 map[keytype]valuetype

例子:
var a map[string]string
var a map[string]int

注意:声明是不会分配内存的需要make初始化

初始化的两种方式:
var map[string]string = map[string][string]{"hello","world"}
或:
var a = make(map[string]string,10)

插入和更新
a["hello"] = "world"

查找
val,ok := a["hello"]

遍历
for k,v := range a{
fmt.println(k,v)
}

删除
delete(a,"hello")

这个操作是安全的,及时这个元素不存在也不会报错,如果一个查找失败将返回value类型对应的零值

长度
len(a)

map是引用类型

注意:map中的元素并不是一个变量,所以我们不能对map的元素进行取址操作

如下:

package main
import "fmt"
func createMap() {
    /*创建map的四种方式
        1) make(map[KeyType]ValueType, initialCapacity)
    2) make(map[KeyType]ValueType)
    3) map[KeyType]ValueType{}
    4) map[KeyType]ValueType{key1 : value1, key2 : value2, ... , keyN : valueN}
    */
    map1 := make(map[string]string, 5)
    map2 := make(map[string]string)
    map3 := map[string]string{}
    map4 := map[string]string{"a": "1", "b": "2", "c": "3", "d": "4"}
    fmt.Println(map1, map2, map3, map4)
}
//填充和遍历
func traversalMap() {
    map1 := make(map[string]string)
    map1["a"] = "1"
    map1["b"] = "2"
    map1["c"] = "3"
    for index, val :=range map1 {
        fmt.Printf("%s->%s
", index, val)
    }
}
//更新,查找,删除
func updateMap() {
    fmt.Println("-----------------------------")
    map4 := map[string]string{"a": "1", "b": "2", "c": "3", "d": "4"}
    //查找,返回key对应的value,和是否存在的布尔值
    value, exist := map4["a"]
    fmt.Printf("%v->%v
", exist, value)
    fmt.Println("=============================")
    //更新
    map4["a"] = "8"
    fmt.Printf("%v
", map4)
    //删除
    delete(map4, "b")
    fmt.Printf("%v
", map4)
}
func main() {
    createMap()
    traversalMap()
    updateMap()
}

转自https://www.cnblogs.com/zhaof/p/8129424.html

免责声明:文章转载自《golang-指针,函数,map》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Arch/GentooLinux开发环境构建与常用软件一览ubuntu13.04下gcc4.5.1的安装下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

java微信二次第三方开发,token认证,消息事件接收,图文素材库,自定义菜单等功能

基于之前的文章SSM配置的项目:http://www.cnblogs.com/mangyang/p/5168291.html 来进行微信第三方开发, 微信二次开发,官方还是网上有很多介绍了,这里就不在进行讲述了 直接上干货。 首先 与微信对接,服务器配置,需要80端口和443端口开放的服务器,这里推荐 使用 python 的pagekite,一款反向代理...

比NotePad++更好的文本代码(C#)编辑器Sublime Text

前言  前两天在博客园看到@晴天猪的博客发表的关于他使用的代码编辑器,自己索性试了一下,果断好用,自己也来记录一下。以便以后配置使用。接下来我配置的主要是简单的编译C#代码的。 配置一调用C#编译器  我现在电脑的系统为Win7哦。我要将C#编译器的csc.exe文件添加到环境变量中。 首先我的电脑==右键属性==高级系统设置==环境变量==系统变量==变...

Windows PowerShell初体验——.NET对象支持

我个人很少用到Linux/Unix 操作系统. 对于不少Linux/Unix管理员在系统任务操作Shell一直保持很难理解. 后来从朋友公司听说他们测试队伍中专门保留了一个脚本Scirpt Shell 测试小组. 我一时更纳闷了. 当然这个问题知道我碰到Windows PowerShell-Windows出的一套Shell工具后 才渐渐理解. Window...

链表面试题

1、逆置链表 假设链表现在是 4->3->2->1->NULL逆置后的链表是 1->2->3->4->NULL步骤:第一步:先把4用临时指针tmp保存起来,cur指向下一个节点,即cur指向3 第二步:令tmp指向newNode,4是第一个节点,则4的next为NULL,即令tmp->next =ne...

UEditor的使用

UEditor 是目前项目正在使用的富文本编辑器。 基本知识 ———————————————————————————————————— 1.依赖:不依赖任何第三方库,可单独使用 2.使用: (1)文件管理:为简化管理开发,建议将UEditor单独放在一个文件夹内,不建议重新组织文件结构(可删除example、src等文件夹) (2)引入及初始化:需要引入c...

golang闭包和range,关于闭包内使用外部变量

遇到经典问题 func mian() { resslice := []int{1, 2, 3, 4} for _, v := range resslice { fmt.Println(v) defer fun1(v) } } func fun1(value int) { fmt.Println(value) }   输出结果为...