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% 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容

  • 1.变量 Go 语言变量名由字母、数字、下划线组成,其中首个字母不能为数字。声明变量的一般形式是使用 var 关键...
    silencefun阅读 275评论 0 0
  • 1. 变量 1.1 变量声明 变量声明的标准格式:var <变量名称> <变量类型>变量名称的首字母大小写则决定该...
    VienFu阅读 237评论 0 2
  • 变量: 变量是计算机语言中能储存特定类型计算结果或能表示特定类型值的抽象概念 声明变量及变量赋值: go语言中声明...
    SUN_LEON阅读 412评论 0 0
  • 1.变量声明,初始化与赋值 2.变量可见性规则; 3.常量,常量的声明和iota的使用 变量声明:var 变量名 ...
    胜猿阅读 249评论 0 0
  • Go语言数据类型 Go语言本质是用C语言编写的一套高级开发语言, 所以Go语言中的数据类型大部分都是由C语言演变而...
    极客江南阅读 923评论 0 6