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% 
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

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

友情链接更多精彩内容