go语言变量与常量

变量是一个抽象概念,它有内存地址,数据类型和值组成:

  • 内存地址:给出了变量在内存中存储的其实地址,一般占用4或8字节(32位、64位机器)。
  • 数据类型:定义了变量占用内存的大小。
  • 值:表示内存地址中存放的内容。

基本类型

go语言内置了如下这些基本数据类型

整型

  • 无符号:uint, uint8, uint16, uint32, uint64, uintptr ,byte,值范围为0 ~ 2^n-1 ,uintptr初始值为nil,其他初始值为0,uint和uintptr长度跟随硬件平台而变,uintptr能够容纳当前硬件平台的一个指针,byte与uint8等价,表示一个字节。
  • 有符号:int , int8, int16, int32, int64,rune,值范围为-2^(n-1) ~ 2^(n-1)-1,初始值为0,其中int类型的长度跟随硬件平台而变,rune用来表示一个unicode字符,与int32等价,可以互换使用。

整型中byte和rune也叫字符型,byte是uint8的别称,用来表示一个ASCII字符。
rune是int32的别称,用来表示一个Unicode字符,Unicode字符长度不一,一般用十六进制表示

var ch1 byte = 'A'    //字符
var ch2 byte = 65     //十进制
var ch3 byte = '\x41' //十六进制,以 ‘ \x ’开头
var ch4 byte = '\101' //八进制,以 ‘ \ ’开头
//Unicode字符A的定义方式
var ch5 rune = '\u0041'      //用小u表示4字节字符
var ch6 int64 = '\U00000041' //大U表示8字节
fmt.Printf("ASCII 字符: %c,%c,%c,%c \n", ch1, ch2, ch3, ch4)
fmt.Printf("Unicode 字符: %c,%c, 对应整数: %v,%d, 对应十六进制表示:%U", ch5, ch6, ch5, ch5, ch5)

// 输出
// ASCII 字符: A,A,A,A 
// Unicode 字符: A,A, 对应整数: 65,65, 对应十六进制表示:U+0041%  

Unicode,ASCII都是字符集,Unicode是ASCII的超集。
UTF-8是可变长编码规则,可编码长度从1~4字节不等,优势是不存在字节序问题,所以很适合在网络上传输。

浮点型

  • float32, float64:浮点型都是有符号的,应该优先使用float64,因为float32能精确表示的浮点数并不多,误差容易扩散。浮点型定义时可以只写整数或小数部分,但是小数点不能省。可以使用科学计数法来书写,e或E指定指数部分。
var f1 float64 = 1.
var f2 = .000002
f3, f4 := 1.2e12, 3.5E-12

复数类型

  • complex64, complex128:复数

布尔型

  • bool: 取值为true和false,不能参与运算,逻辑运算会产生bool值,go语言中只有相同数据类型才能进行比较,如果是类对象,需要实现相同的接口才能比较。但是可以转换成相同类型后进行比较。
    go语言逻辑运算也会截断,如(a>b && a<c),如果a>b为false,则直接返回false而不会比较a和c。

变量定义方式

  • 1、标准格式
    go语言变量类型是后置的
var 变量名 类型
var a int
  • 2、缺省类型方式
    go语言根据初始化值自动推导类型,这种方式必须显式初始化。
var b = 1
  • 3、批量定义
var(
    c int = 10
    d float32
    e []byte
)
  • 4、简短格式
    这种方式只能用在函数内部,必须显式初始化,在局部变量定义中比较常用。
f := 1.0
f1,f2,f3 := 1, 1.0, "aaa"

需要注意,同一作用域内不能重复定义变量

var g int = 10
g := 12  //这一行将会报错,g重复定义

不同作用域可以重复定义,go会使用相同作用域内的变量,不会覆盖

var h int = 10
{
	h := 12.0
	fmt.Printf("h = %f", h)
}
fmt.Printf("h = %d", h)
 //输出: h = 12.000000, h = 100

在简短定义多个变量时,只要左边有一个新定义的变量,其他变量就可以重复赋值(注意不是重复定义,因为赋值类型必须和之前定义的一致)

//这个例子中,i重复复制1.0,但是类型任然是int,但是会把2.0强转为int。
i := 1
i, i1 := 2.0, "xxx"
fmt.Printf("type of i is :  %T, i = %d, i1 = %s", i, i, i1)
//输出:type of i is :  int, i = 2, i1 = xxx

匿名变量

go语言中定义的变量如果没有使用就会报错,从根源上杜绝了变量的泛滥。
然而有些函数的多个返回值有时候我们并不全都需要,但是全都定义又必须要使用,这时候就需要用到匿名变量。

匿名变量用一个下划线"_"表示,不分配内存,可以重复定义,任何类型变量都可以赋值给它,但是不能使用它,也不能将它赋值给其他变量和参与运算(即只能作为左值)

//正常情况下定义两个返回值
conn, err := net.Dial("tcp", "127.0.0.1")
fmt.Printf("conn  = %v, err = %v \n", conn, err)
//不关系err这个返回值时
conn1, _ := net.Dial("tcp", "127.0.0.1")
//当所有返回值都不关心时,直接不定义返回值就可以,不能所有返回值都用匿名变量
// _, _ := net.Dial("tcp", "127.0.0.1")

类型转换

  • go语言没有隐式类型转换,所有需要转换的类型都必须显式申明:
var a TypeA
var b TypeB = TypeB(a)  //将a的值强制转换为TypeB类型并赋值给b,a不变
c := 1.0
var b int = int(c)
  • 只有底层类型相同(如int16和int32互转)的变量才能相互转化,不同底层类型(如bool和int)互转将会编译错误。
  • 短类型转为长类型没有风险,长类型转为短类型有精度丢失风险。

作用域

作用域表示可访问某变量的范围,go语言有两种作用域

  • 1、局部作用域
    定义在局部作用域中的变量称为局部变量,局部变量出了作用域就会被销毁,像函数参数、返回值、函数内部定义的变量都是局部变量,函数调用一旦完成就这些变量都会被销毁。
    在函数内部也可以用大括号{ }来定义一个更小的局部作用域。
func foo(a, b int) (c, d int) {
	//通过{}定义局部作用域,i出了{}就没了,所以只能在{}内使用
	{
		i := 100
		fmt.Printf("自定义局部作用域: i = %d \n", i)
	}
	c, d = b, a
	fmt.Printf("函数参数和返回值都是局部变量: a = %d,b = %d,c = %d, d = %d \n", a, b, c, d)
	return
}
  • 2、全局作用域
    函数外部定义的变量就是全局变量,这些变量的生命周期与进程相同,在进程结束时才会销毁。
  • 全局变量必须使用var关键字进行定义
  • 全局变量可以被本文件中的所有函数访问,如果需要在其他源文件中访问变量,需要将变量首字母大写(即通过变量名大小写控制访问权限),并在需要访问的文件中通过import导入当前源文件。
var AAA int = 10 //外部文件可以访问
var bbb = 123    //外部文件无法访问

func main() {
...
}

常量

  • 常量是与变量相对于的一个概念,他们都是对应一块内存,只是变量可以被修改,常量一旦定义就不能被修改。
  • 常量在编译时就创建,只能定义bool,字符串和数字型(包括整型,字符,浮点型,复数)
  • 常量的算数、逻辑、比较运算的结果也是常量
  • len、cap、real、image、complex、unsafe.Sizeof的调用返回是常量。

定义方式和变量类似

//定义变量
var a int = 1
//定义常量
const b int = 2 
//同时声明多个常量
const(  
    c = 1.0
    d = "str"
)
//同时申明多个常量时,未赋值的常量会复用前一个常量的值
const(
    e = 1
    f
    g = 2
    h
)
fmt.Println(e,f,g,h) //输出:1 1 2 2
//使用iota常量生成器
const(
    i = iota
    j
    k
    l
)
fmt.Println(i,j,k,l) //输出:0 1 2 3

总结

  • go语言行尾不用加分号,go语言没有分号。
  • go语言变量类型是后置的,所有变量定义即自动初始化为初始值,不存在c语言的声明和定义的区别。
  • 简短定义变量只能使用在函数内部。
  • 同一作用域不能重复定义变量,不同作用域可以重复定义,简短定义左边至少有一个新变量。
  • 首字母大写的变量或函数可以被import该文件的外部文件访问。


完整示例代码

/*
 * 这个文件主要介绍变量的相关内容
 */

package main

import (
	"fmt"
	"net"
)

func foo(a, b int) (c, d int) {
	//通过{}定义局部作用域,i出了{}就没了,所以只能在{}内使用
	{
		i := 100
		fmt.Printf("自定义局部作用域: i = %d \n", i)
	}
	c, d = b, a
	fmt.Printf("函数参数和返回值都是局部变量: a = %d,b = %d,c = %d, d = %d \n", a, b, c, d)
	return
}

var AAA int = 10 //外部文件可以访问
var bbb = 123    //外部文件无法访问

func main() {
	//变量标准定义方式,自动初始化
	var a int
	fmt.Printf("变量标准定义模式,自动初始化为: a = %d \n", a)

	//缺省类型的定义方式,自动推到类型,明确初始化
	var b = 1
	fmt.Printf("缺省类型的定义方式,自动推到类型: type fo b is %T \n", b)

	//批量定义变量
	var (
		c int = 12
		d float32
		e []byte
	)
	fmt.Printf("批量定义变量: c = %d,d = %f,e = %s \n", c, d, e)

	//简短格式,缺省var和类型,可同时定义多个变量
	f := 1.2
	f1, f2, f3 := 1, 1.2, "xxxx"
	fmt.Printf("简短格式定义变量,type of f is : %T, f = %f ,f1 = %d,f2 = %f,f3 = %s\n", f, f, f1, f2, f3)

	//同一作用域不能重复定义变量
	var g int = 10
	//g := 12   //这一行将会报错,重复定义
	fmt.Printf("相同作用域内重复定义会出错: g = %d\n", g)

	//不同作用域可以重复申明,go会使用相同作用域内的变量
	var h = 100
	{
		h := 12.0 //较小作用域内定义
		fmt.Printf("较小作用域内重复定义: h = %f, ", h)
	}
	fmt.Printf("较大作用域内定义的变量没有被覆盖: h = %d \n", h)

	//例外情况,简短定义只要左边有一个新变量,其他变量可以重复之前定义过的变量
	i := 1
	i, i1 := 2.0, "xxx"
	fmt.Printf("简短定义只要左边有一个新变量,其他变量可以重复之前定义过的变量: type of i is :  %T,i = %d, i1 = %s \n", i, i, i1)

	//变量交换
	j, k := 1, 2
	fmt.Printf("变量交换: j=%d,k=%d , ", j, k)
	j, k = k, j
	fmt.Printf(" 交换后: j=%d,k=%d \n", j, k)

	// 匿名变量
	//正常情况下定义两个返回值
	conn, err := net.Dial("tcp", "127.0.0.1")
	fmt.Printf("conn  = %v, err = %v , ", conn, err)
	//不关系err这个返回值时
	conn1, _ := net.Dial("tcp", "127.0.0.1")
	fmt.Printf("conn1 = %v \n", conn1)
	//当所有返回值都不关心时,直接不定义返回值就可以,不能所有返回值都用匿名变量
	// _, _ := net.Dial("tcp", "127.0.0.1")

	foo(1, 2)
	fmt.Printf("全局变量:AAA = %d,bbb = %d \n", AAA, bbb)

	//byte和rune使用
	var ch1 byte = 'A'    //字符
	var ch2 byte = 65     //十进制
	var ch3 byte = '\x41' //十六进制,以 ‘ \x ’开头
	var ch4 byte = '\101' //八进制,以 ‘ \ ’开头
	//Unicode字符A的定义方式
	var ch5 rune = '\u0041'      //用小u表示4字节字符
	var ch6 int64 = '\U00000041' //大U表示8字节

	fmt.Printf("ASCII 字符: %c,%c,%c,%c \n", ch1, ch2, ch3, ch4)
	fmt.Printf("Unicode 字符: %c,%c, 对应整数: %v,%d, 对应十六进制表示:%U", ch5, ch6, ch5, ch5, ch5)
}

输出

变量标准定义模式,自动初始化为: a = 0 
缺省类型的定义方式,自动推到类型: type fo b is int 
批量定义变量: c = 12,d = 0.000000,e =  
简短格式定义变量,type of f is : float64, f = 1.200000 ,f1 = 1,f2 = 1.200000,f3 = xxxx
相同作用域内重复定义会出错: g = 10
较小作用域内重复定义: h = 12.000000, 较大作用域内定义的变量没有被覆盖: h = 100 
简短定义只要左边有一个新变量,其他变量可以重复之前定义过的变量: type of i is :  int,i = 2, i1 = xxx 
变量交换: j=1,k=2 ,  交换后: j=2,k=1 
conn  = <nil>, err = dial tcp: address 127.0.0.1: missing port in address , conn1 = <nil> 
自定义局部作用域: i = 100 
函数参数和返回值都是局部变量: a = 1,b = 2,c = 2, d = 1 
全局变量:AAA = 10,bbb = 123 
ASCII 字符: A,A,A,A 
Unicode 字符: A,A, 对应整数: 65,65, 对应十六进制表示:U+0041% 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值