无类型常量和类型推断

举报
码乐 发表于 2024/07/29 10:02:50 2024/07/29
【摘要】 1 简介本文总结了无类型常量的概念和使用。无类型常量是指没有明确类型的常量,包括无类型的布尔型、整数、字符、浮点数、复数和字符串。 2 无类型常量: 只有常量可以是无类型的。Go 中的常量可以是有类型化的,也可以是非类型化的。例如,给定以下字符串文本: "go"有人可能会说,文字的类型是string ,但是,这在语义上是不正确的。相反,文本是非类型化字符串常量。它是一个字符串(更准确地...

1 简介

本文总结了无类型常量的概念和使用。无类型常量是指没有明确类型的常量,包括无类型的布尔型、整数、字符、浮点数、复数和字符串。

2 无类型常量的例子

			只有常量可以是无类型的。

Go 中的常量可以是有类型化的,也可以是非类型化的。例如,给定以下字符串文本:

	"go"

有人可能会说,文字的类型是string ,但是,这在语义上是不正确的。

相反,文本是非类型化字符串常量。它是一个字符串(更准确地说,其默认类型是string ),

但它不是 Go 值,因此在键入的上下文中分配或使用它之前没有类型。这是一个微妙的区别,但理解之后变得很有用。

  • 例子

      func main() {
      const golang = "go"
      const typedgolang string = "go"
    
      var s string
      s = golang      // 工作正常
      s = typedgolang // 正常
      fmt.Printf("%T, %v \n", s, s)
    
      type MyString string
      var mys MyString
      mys = golang //工作正常
      //mys = typedgolang // 无法使用 typedgolang (type string) 作为 MyString的类型推导
    
      fmt.Printf("%T,%v \n", mys, mys)
     }
    

    当我们尝试在具有类型的上下文中分配这些常量时,这种差异就会发挥作用。

3 无类型常量

golang有六种未明确类型的常量类型,分别是无类型的布尔型、无类型的整数、无类型的字符、无类型的浮点数、无类型的复数、无类型的字符串。

通过延迟明确常量的具体类型,无类型的常量不仅可以提供更高的运算精度,而且可以直接用于更多的表达式而不需要显式的类型转换。

常量表达式

	fmt.Println(YiB/ZiB) // "1024"

math.Pi无类型的浮点数常量,可以直接用于任意需要浮点数或复数的地方:

	var x float32 = math.Pi
	var y float64 = math.Pi
	var z complex128 = math.Pi

如果math.Pi被确定为特定类型,比如float64,那么结果精度可能会不一样,同时对于需要float32或complex128类型值的地方则会强制需要一个明确的类型转换:

	const Pi64 float64 = math.Pi
	var x float32 = float32(Pi64)
	var y float64 = Pi64
	var z complex128 = complex128(Pi64)

对于常量面值,不同的写法可能会对应不同的类型。
例如0、0.0、0i和 \u0000虽然有着相同的常量值,
但是它们分别对应无类型的整数、无类型的浮点数、无类型的复数和无类型的字符等不同的常量类型。

同样,true和false也是无类型的布尔类型,字符串面值常量是无类型的字符串类型。

过除法运算符/会根据操作数的类型生成对应类型的结果。因此,不同写法的常量除法表达式可能对应不同的结果

	var f float64 = 212
	fmt.Println((f - 32) * 5 / 9) // "100"; (f - 32) * 5 is a float64
	fmt.Println(5 / 9 * (f - 32)) // "0"; 5/9 is an untyped integer, 0
	fmt.Println(5.0 / 9.0 * (f - 32)) // "100"; 5.0/9.0 is an untyped float
  • 常量的隐式转换

当一个无类型的常量被赋值给一个变量的时候,就像下面的第一行语句,

或者出现在有明确类型的变量声明的右边,如下面的其余三行语句,无类型的常量将会被隐式转换为对应的类型,如果转换合法的话。

	var f float64 = 3 + 0i // untyped complex -> float64
	f = 2 // untyped integer -> float64
	f = 1e123 // untyped floating-point -> float64
	f = 'a' // untyped rune -> float64

它们相当于

	var f float64 = float64(3 + 0i)
	f = float64(2)
	f = float64(1e123)
	f = float64('a')

对于一个没有显式类型的变量声明(包括简短变量声明),常量的形式将隐式决定变量的默认类型,就像下面的例子:

	i := 0 // untyped integer; implicit int(0)
	r := '\000' // untyped rune; implicit rune('\000')
	f := 0.0 // untyped floating-point; implicit float64(0.0)
	c := 0i // untyped complex; implicit complex128(0i)	

当尝试将这些无类型的常量转为一个接口值时(见第7章),这些默认类型将显得尤为重要,因为要靠它们明确接口对应的动态类型。

	fmt.Printf("%T\n", 0) // "int"
	fmt.Printf("%T\n", 0.0) // "float64"
	fmt.Printf("%T\n", 0i) // "complex128"
	fmt.Printf("%T\n", '\000') // "int32" (rune)

4 类型推断

  • 值得一说的类型推断

类型是从它们的初始化表达式(类型)推断出来的。 随着 Go 1.18 中泛型的引入,Go 的类型推断能力 得到了显着的扩展。

为什么要进行类型推断?在非泛型 Go 代码中,省略类型的效果在简短的变量声明中最为明显。 这样的声明结合了类型推断和一点语法 糖——省略关键词的能力——变成一个非常紧凑的声明。 请考虑以下映射var变量声明

		var m map[string]int = map[string]int{}

		m := map[string]int{}

省略左侧的文字可以消除重复,同时:=提高可读性。

对于类型推断,类型化参数优先于非类型化参数。 仅当分配了类型参数时,才会考虑使用非类型化常量进行推理 , 还没有推断类型。 在对函数 的前三次调用中,变量确定 的推断类型: 它的类型是确定的 . 在这种情况下,类型推断将忽略非类型化常量,并且调用的行为完全相同 好像是用 显式实例化的。

如果仅使用非类型常量参数调用,它会变得更有趣。

在这种情况下,类型推断会考虑非类型化常量的默认类型。 作为快速提醒,以下是 Go 中可能的默认类型:

	实例        常量类型            	  默认类型        顺序

	true        boolean 常量           bool
	42          integer 常量           int             列表前端
	'x'         rune 常量              rune               |
	3.1416      floating-point 常量    float64            v
	-1i         complex 常量           complex128      列表后端
	"gopher"    string 常量            string

参数顺序依赖性。某些时候函数第一个与参数顺序依赖关系有关。 我们希望从类型推断中得到的一个重要属性是,推断出相同的类型 无论函数参数的顺序如何(和相应的参数) 该函数的每次调用中的顺序)。

另外就泛型的目前状态而言,go必须始终显式实例化泛型类型。

首先,对于类型实例化,类型推断 只有类型参数可以使用;没有其他论点,就像 函数调用。

必须始终至少提供一个类型参数 (除了类型约束只规定了一种可能的病理情况 所有类型参数的类型参数)。

类型的类型推断仅对完成部分 实例化类型,其中所有省略的类型参数都可以从 由类型约束得出的方程;即至少有两种类型 参数。go认为这不是一个常见的情况。

5 总结

这些常量可以提供更高的运算精度,并且可以直接用于更多的表达式而不需要显式的类型转换。

当无类型的常量被赋值给一个变量时,会发生隐式转换为对应的类型。类型推断是从初始化表达式中推断出类型的,而在泛型的引入中,类型推断能力得到了显着的扩展。

在类型推断中,类型化参数优先于非类型化参数。

最后,对于类型实例化,类型推断只有类型参数可以使用,必须至少提供一个类型参数。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。