Go学习笔记 -- 程序实体之变量

前言

       在 Go 语言中,程序实体包括常量、变量、函数、结构体和接口。因为 Go 是一种静态类型的编程语言,所以我们在声明常量或者变量的时候,需要直接指定它们的类型,或者让 Go 能判断出他是属于什么类型。
       而且在 Go 语言中,不存在像 Java 语言中的 publicprivate 等访问权限标识符。Go 对程序实体的访问权限控制是通过它们的名字定义来实现的。程序实体名字首字母大写表示它可以被任何程序包访问,名字首字母为小写的程序实体则只能被同一个代码包中的代码所访问。

       以下代码都是配合 Go 语言内置的 flag 包实现的,通过命令行启动代码时传递参数,通过 flag 包解析参数。

变量

变量的声明与赋值

声明变量可以有多种方式:

  • 直接指定类型后使用
    import (
    	"flag"
    	"fmt"
    )
    var name string
    //name = 'test'
    flag.StringVar(&name, "name", "world", "Usage:name") 
    flag.Parse()
    fmt.Printf("hello, %s", name)
    
  • 如果调用的方法指定了返回类型,那么我们可以省略自己指定变量类型的操作
    如下代码 flag.String 方法返回的是一个 *string (字符串的指针类型) 类型的结果赋给了 name,因此这里的 name 代表一个指向字符串值的指针,可以通过 *name 获取其中的值。
    var name = flag.String(&name, "name", "world", "Usage:name") 
    flag.Parse()
    fmt.Printf("hello, %s", *name)
    
  • 使用短变量定义,其实和第二个方法相似,只是省略了 var,使用 := 声明并赋值变量
    name := flag.String(&name, "name", "world", "Usage:name") 
    flag.Parse()
    fmt.Printf("hello, %s", *name)
    
     但是要注意的是, := 左面必须有需要声明的变量,编译才不会报错
    
    name,age := function1()
    name,gender := function2()//编译通过,相当于给name赋值、同时声明gender并为gender赋值
    name,age := function3()//编译出错
    

可重名变量和变量重命名

可重名变量
import "fmt"
func main() {
	var block = map[int]string{0: "zero", 1: "one", 2: "two"}
	{
		block := "inner"
		fmt.Printf("%s", block)
	}
	fmt.Printf("%s", block)
}

以上代码打印结果为

inner
map[%!s(int=0):zero %!s(int=1):one %!s(int=2):two]

       可以发现,两个代码块内外的 block 打印出来的类型完全不一样,甚至一个是值类型,一个是引用类型。其实这个 block 就是可重名变量,代码块内外的两个 block 除了名字相同之外,没有什么关系。
       实际上,当代码块内的代码需要使用 block 这个变量时,会先在当前代码块中寻找,但不会寻找子代码块,若找不到则会到上一层包裹着自己的代码块中寻找,如果到最外层都找不到则会抛出编译异常。

因此,可重名变量具有以下关系:

  • 可重名变量都是在不同的代码块里面的
  • 可重名变量之间没有数据类型的限制,即变量类型可以不相同
  • 可重名变量实际上就是不同的变量,只不过是变量名称相同罢了
  • 可重名变量存在"屏蔽"现象,即存在嵌套关系的代码块,内部代码块的变量会屏蔽外部代码块的同名变量。
变量重声明
import (
	"fmt"
	"io"
	"os"
)
func main() {
	var err error
	n, err := io.WriteString(os.Stdout, "Hello World")
	fmt.Printf(string(n) + "\n")
	fmt.Println(err)
}

其中,在 n,err := io.WriteString(oss.Stdout,“Hello World”) 一行中,是对 n 的声明赋值,并对 err 的重声明和赋值。

变量重声明具有以下特点:

  • 变量在同一个代码块中
  • 变量重声明后的类型必须和第一次声明时保持一致
  • 变量重声明实际上就是对同一个变量的多次声明

判断变量类型

为了避免可重名变量的存在而导致的"屏蔽"现象,我们在使用变量之前,最好先判断一下这个变量的类型,以下提供两种方法。

类型断言

类型断言表达式的语法形式是 x.(T),其中的 x 代表要被判断类型的值,这个值必须是接口类型的, T 表示要判断的类型。
以下代码为例:
因为 test 不是接口类型的,所以我们需要先将其转换为接口类型 interface{}(test)

var test = "ceshi"
value, ok := interface{}(test).(string)
fmt.Println(ok)
fmt.Println(value)
--Result------------------------
true
ceshi

如果 ok 接收类型是否匹配的结果,如果 oktruevalue 接收值
如果 okfalse ,则 value 会按照要检验的类型生成一个初始值或者初始对象。

var test = "ceshi"
value, ok := interface{}(test).(int)
fmt.Println(ok)
fmt.Println(value)
--Result------------------------
false
0
var test2 = []string{"zero", "one", "two"}
value2, ok2 := interface{}(test2).([]int)
fmt.Println(ok2)
fmt.Println(value2)
--Result------------------------
false
[]

当然我们也可以不接收 ok ,直接接收值,但当出现类型不匹配时,Go 就会抛出 Panic 恐慌。

var test2 = []int{1, 2, 3}
value2 := interface{}(test2).([]string)
fmt.Println(value2)
--Result------------------------
panic: interface conversion: interface {} is []int, not []string
switch 语句

还有一种方法,通过 type-switch 实现的类型匹配。

var test2 = []int{1, 2, 3}
switch t := interface{}(test2).(type) {
case string:
	fmt.Println(t)
case []int:
	fmt.Println(t[1])
default:
	return
}
--Result------------------------
2
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mingvvv

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值