Golang常量无法取地址

今天在尝试取常量的地址时出现了报错,会有这样一些场景,嵌套型的struct有些字段是*string或者*int

package maintype Obj struct {Prop1  *stringProp2  *int
}func main() {obj := Obj{Prop1:  &"a string property",Prop2:  &5,}
}
//报错:
Cannot take the address of '"a string property"'
Cannot take the address of '5'

Golang官方的解释是这样的:

For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal. If the evaluation of x would cause a run-time panic, then the evaluation of &x does too.
对于类型为 t 的操作数 x,地址操作 & x 生成类型为 * t 到 x 的指针。操作数必须是可寻址的,即变量、指针间接或片索引操作; 或可寻址结构操作数的字段选择器; 或可寻址数组的数组索引操作。作为可寻址性要求的一个例外,x 也可以是一个(可能是括号中的)复合文本。如果对 x 的求值会引起运行时恐慌,那么对 & x 的求值也会引起恐慌。

不允许使用常量的地址。 可能有以下几个原因:

  1. 常量可能根本没有地址。
  2. 如果可以使用常量值的地址,则可以将**地址(指针)**分配给变量,然后可以通过指针更改该值。
  3. 常量不同于变量的在运行期分配内存,常量通常会被编译器在预处理阶段直接展开,作为指令数据使用,所以常量是无法取地址的【《Go语言学习笔记摘录》】

解决方法

1.声明一个变量,内容和该常量相等,然后对该变量取地址

package maintype Obj struct {Prop1  *stringProp2  *int
}func main() {var p1 string= "a string property"var p2 int = 5obj := Obj{Prop1:  &p1,Prop2:  &p2,}
}

2.定义一个接受常量并返回其地址的函数

s := func(s string) *string { return &s }
i := func(s int) *int { return &i }obj := Obj{Prop1:  s("a string property"),Prop2:  i(5),Status: s(statuses.Awesome)
}

之所以可行,是因为在将常量作为参数传递给函数时,会复制该常量成为形参变量,这意味着在函数中创建的指针不是指向常量的地址,而是指向变量【形参】的地址。

Go语言常量特点

参考
Go 语言的常量是一种在源码编译期间被创建的语法元素。这是在说这个元素的值可以像变量那样被初始化,但它的初始化表达式必须是在编译期间可以求出值来的。而且,Go 常量一旦声明并被初始化后,它的值在整个程序的生命周期内便保持不变。这样,我们在并发设计时就不用考虑常量访问的同步,并且被创建并初始化后的常量还可以作为其他常量的初始表达式的一部分。但Go 语言规范规定,Go 常量的类型只局限于 Go 基本数据类型,包括数值类型、字符串类型,以及只有两个取值(true 和 false)的布尔类型。而在C语言中const 关键字修饰的标识符本质上依旧是变量,它甚至无法用作数组变量声明中的初始长度(除非用 GNU 扩展 C)。比如:

const int size = 5;
int a[size] = {1,2,3,4,5}; // size本质不是常量,这将导致编译器错误

1. 无类型常量
Go 语言对类型安全是有严格要求的:即便两个类型拥有着相同的底层类型,但它们仍然是不同的数据类型,不可以被相互比较或混在一个表达式中进行运算。这一要求不仅仅适用于变量,也同样适用于有类型常量(Typed Constant)中

type myInt int
const n myInt = 13
const m int = n + 5 // 编译器报错:cannot use n + 5 (type myInt) as type int in const initializerfunc main() {var a int = 5fmt.Println(a + n) // 编译器报错:invalid operation: a + n (mismatched types int and myInt)
}
//显示转型:
type myInt int
const n myInt = 13
const m int = int(n) + 5  // OKfunc main() {var a int = 5fmt.Println(a + int(n))  // 输出:18
}

上述例子的问题也可以用无类型常量来解决,无类型常量也不是说就真的没有类型,它也有自己的默认类型,不过它的默认类型是根据它的初值形式来决定的。像下面代码中的常量 n 的初值为整数形式,所以它的默认类型为 int,但常量 n 的默认类型 int 与 myInt 并不是同一个类型啊,为什么可以放在一个表达式中计算而没有报编译错误呢?【隐式转型】

type myInt int
const n = 13 //无类型常量func main() {var a myInt = 5fmt.Println(a + n)  // 输出:18
}

2. 隐式转型
隐式转型说的就是,对于无类型常量参与的表达式求值,Go 编译器会根据上下文中的类型信息,把无类型常量自动转换为相应的类型后,再参与求值计算,这一转型动作是隐式进行的。但由于转型的对象是一个常量,所以这并不会引发类型安全问题,Go 编译器会保证这一转型的安全性。不过,如果 Go 编译器在做隐式转型时,发现无法将常量转换为目标类型,Go 编译器也会报错:

const m = 1333333333var k int8 = 1
j := k + m // 编译器报错:constant 1333333333 overflows int8

3. 实现枚举
Go 语言其实并没有原生提供枚举类型。
Go 的 const 语法提供了“隐式重复前一个非空表达式”的机制,比如下面代码:

const ( Apple, Banana = 11, 22 Strawberry, Grape Pear, Watermelon
)

这个代码里,常量定义的后两行并没有被显式地赋予初始值,所以 Go 编译器就为它们自动使用上一行的表达式,也就获得了下面这个等价的代码:


const (Apple, Banana = 11, 22Strawberry, Grape  = 11, 22 // 使用上一行的初始化表达式Pear, Watermelon  = 11, 22 // 使用上一行的初始化表达式
)

Go 在这个特性的基础上又提供了“神器”:iota,iota 是 Go 语言的一个预定义标识符,它表示的是 const 声明块(包括单行声明)中,每个常量所处位置在块中的偏移值(从零开始)。同时,每一行中的 iota 自身也是一个无类型常量,可以像前面我们提到的无类型常量那样,自动参与到不同类型的求值过程中来,不需要我们再对它进行显式转型操作。
Go 标准库中 sync/mutex.go 中的一段基于 iota 的枚举常量的定义:


// $GOROOT/src/sync/mutex.go
const ( mutexLocked = 1 << iota //1 << 0,也就是 1mutexWoken //隐式重复前一个非空表达式:mutexWorken = 1 << iota = 1<<1 = 2mutexStarving //隐式重复前一个非空表达式:mutexWorken = 1 << iota = 1<<2 = 4mutexWaiterShift = iota //3starvationThresholdNs = 1e6 //1e6本身
)

如果一个 Go 源文件中有多个 const 代码块定义的不同枚举,每个 const 代码块中的 iota 也是独立变化的,也就是说,每个 const 代码块都拥有属于自己的 iota

Golang常量无法取地址相关推荐

  1. golang中new、make及取地址符()

    new简介及使用方式 new() 用于返回类型指针,这个操作:分两步,第一步:初始化一个变量为零的值,第二步:生成一个指向类型变量的地址. &Type 返回类型变量的地址,这个操作:分两步,第 ...

  2. C++ 笔记(14)— 指针(指针声明、取地址、取值、new/delete、NULL指针、指针运算、指针数组、数组指针、指针传递给函数、从函数返回指针)

    1. 声明指针 指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址.就像其他变量或常量一样,您必须在使用指 针存储其他变量地址之前,对其进行声明. 指针变量声明的一般形式为: type * ...

  3. 数组名和数组名取地址的区别

    原文地址:http://blog.csdn.net/daniel_ice/article/details/6857019 以下代码会打印出什么样的日志呢? [cpp]view plaincopypri ...

  4. 对指针变量取地址_C语言指针简介(amp;和*运算符)

    取地址符(&) 和  取值符(*) (1)& 运算符 :用于取一个对象的地址 例如:int *p;    p = &c;    将c的地址赋值给指针变量p,我们称p为 &quo ...

  5. C语言的数组名和对数组名取地址

    *************************************************** 更多精彩,欢迎进入:http://shop115376623.taobao.com ****** ...

  6. c语言地址有什么作用是什么,C语言中取地址运算符是什么?

    在C语言中取地址运算符是"&"."&"作为一元运算符,结果是右操作对象的地址:地址本身是一个抽象的概念,用于表示对象在存储器中的逻辑位置. 在C ...

  7. c语言函数变量地址符,C语言中取地址符做函数形参?—— 引用的讨论

    取地址符&做函数形参? C语言强大且危险 引入 这个问题花去了整整一天的研究. 先看一段严蔚敏的<数据结构>中栈的例程: 这里面的&S第一遍看的时候想当然的认为是取了SqS ...

  8. 数组名和数组名取地址

    在C中,在几乎所有使用数组的表达式中,数组名的值是个指针常量,也就是数组第一个元素的地址. 它的类型取决于数组元素的类型: 如果它们是int类型,那么数组名的类型就是"指向int的常量指针& ...

  9. C语言的一维数组名和对数组名取地址

    逐步分析,下面是一段验证这个问题的代码: #include<stdio.h> int main() { int a[10]; printf("a:\t%p\n", a) ...

  10. C语言数组名、数组名取地址、数组首元素地址之间的关系

    C语言中数组名a.数组名取地址&a.数组首元素地址&a[0]三者的概念有点绕,花了点时间好好琢磨了一下,将自己的理解记录下来,如有错误之处,欢迎赐教. 首先看下面的一小段代码: #in ...

最新文章

  1. 如何在电脑上安装python-在电脑上安装python的方法
  2. 23种设计模式C++源码与UML实现--组合模式
  3. 算法导论系列:分治算法
  4. 使用NAGIOS监控网络、系统及服务
  5. Angular jasmine如何从detectChange触发refreshView进而执行到Component的hook实现
  6. 城管威逼交警“让老百姓笑话”
  7. JAVA--位移运算符详细分析【转载】
  8. JAVA的项目文件夹_Java中Project项目文件夹的绝对路径
  9. 《Troubleshooting Windows 7 Inside Out》文摘-1
  10. 论文查重 降重复度?如何进行毕业论文查重--总结贴
  11. 微信公众号爬虫开发-常见问题汇总
  12. 如何下载VS2015社区版
  13. c语言求最小公倍数——三种方法
  14. 51单片机usb烧录电路_51单片机怎么用usb烧写程序
  15. find+sed考试题及生产实战解决案例分享(考试答案系列)
  16. 微信公众号发送红包(源码)
  17. SVG 2D入门4 - 笔画与填充
  18. 使用自定义注解实现接口的参数校验
  19. 1-14 Burpsuite Repeater介绍
  20. openwrt 自启动实现4G路由器功能总结

热门文章

  1. 简单实用的查询ip地址、mac地址,修改ip地址的方法,ping命令检测网络是否通畅
  2. 机器学习与量化交易项目班 [从零搭建自动交易系统]
  3. JAVA 实现《萝卜勇者》游戏
  4. hibernate(lazy加载)的意思
  5. Python3使用SMTP协议发送电子邮件
  6. markdown实心圆点空心圆点、层级
  7. [答疑]能举一个人取代业务实体的例子吗
  8. ros机器人开发概述
  9. Python量化投资——年化收益26%,一个大小盘轮轮动量化投资策略的回测效果
  10. python批量查询ip归属地_python查询ip归属地