13 - 赋值与类型

我通常理解的最简单的表达式赋值,可以理解为 “x = 1”,但是在 C++ 当中我们还有左值引用右值引用,但是在 go 语言当中,我们出了有普通赋值之外,还有多元赋值等。

一、赋值

x = 1  // 命名变量赋值
*p = true   // 通过指针间接赋值
person.name = "bob"  // 结构体字段赋值
count[x] = count[x] * scale  // 数组、slice、或者 map 的元素赋值

v := 1
v++   // 2  等价于 v = v + 1
++v   		// error 
v = i++   // error,错误赋值方式,自增是语句而不是表达式

// 二元算术运算和赋值语句的一个简洁形式
count[x] *= scale

C/C++++ii++ 是一个表达式也是一条语句,编译会成功,但是在 go 当中 ++i 的写法会导致编译错误, v = i++ 也会导致编译错误,因为 go 语言严格的语法格式决定 i++ 仅仅只是一条语句,可独立存在其结果和 i = i + 1 一致。

二、元组赋值

在 go 语言当中支持多元赋值.在赋值前,赋值语句右边的表达式将会进行求职,然后在统一更新左边对应变量的值.

x, y := 1, 2
x, y = y, x
i, j, k = 1, 2, 3

map 查找、类型断言或通道接收出现在赋值的右边时,并不一定都是产生两个结果,也可能只是产生一个结果。
对于只产生一个结果的情况, map 查找失败时会返回零值,类型断言失败会发送运行时 panic 错误,通道接收失败时也会返回零值(堵塞不算失败)。

v = m[key]  // map 查找,失败时候返回零值
v = x.(T)  	// type 断言,失败时 panic 错误
v = <-ch	// 管道接收,失败是返回零值

_, ok = m[key] // map 返回2个值
_, ok = mm[""], false // map 返回1个值
_ = mm[""]		//map 返回1个值

_, err = io.Copy(dst, src) // 丢弃字节数
_, ok = x.(T)	// 只检测类型,忽略具体指

三、可赋值性

medals := []string{"gold", "silver", "bronze"}  // 隐式的对每个slice的元素进行了复制

//和上述的代码类似写法
medals[0] = "gold"
medals[1] = "silver"
medals[2] = "bronze"

然而在 map chan 中也有类似的隐式赋值行为。但是必须满足的情况就是左边的变量和右边最终求得的值必须是相同的数据类型,才能满足赋值情况。
可赋值性的规则

  • 类型必须完全匹配
  • nil 可赋值给任意指针类型和引用类型的变量

四、类型和类型转化

以下是新类型的声明形式:

type 类型名称 底层类型

新类型和底层类型虽然由相同的底层类型但是他们不兼容。
类型声明语句一般出现在包一级,因此如果新创建的类型名字的首字符大写,则在外部包也可以使用。
示例

type byte uint8
type Second uint32
type Year uint32
//...

这有点类似 C/C++ typedef 操作,为数据类型起一个别名。但是在 go 语言对于数据类型作了严格的要求,不同的数据类型之间是不能做任何赋值运算和逻辑运算。可以通过 T(x) 作类型转(指针类型转化一般为(*T)(0)的形式)。

下面我们做了一关于关于 类型的试验:
// tempconv.go

package tempconv

import "fmt"

type Celsius float64    // 摄氏温度
type Fahrenheit float64 // 华氏温度

const (
    AbsoluteZeroC Celsius = -273.15 // 绝对零度
    FreezingC     Celsius = 0       // 结冰点温度
    BoilingC      Celsius = 100     // 沸水温度
)

// conv.go

package tempconv

func CToF(c Celsius) Fahrenheit {
    return Fahrenheit(c * 9 / 5 + 32)
}

func FToC(f Fahrenheit) Celsius {
    return Celsius((f - 32) * 5 / 9)
}

tempconv 包位于路径

$GOPATH/gopl/ch2/tempconv

CelsiusFahrenheit 类型的算术运算行为和底层的 float64 类型是一样的,正如我们所期望的那样, 不同类型不能做运算

fmt.Printf("%g\n", BoilingC-FreezingC) // "100" °C
boilingF := CToF(BoilingC)
fmt.Printf("%g\n", boilingF-CToF(FreezingC)) // "180" °F
fmt.Printf("%g\n", boilingF-FreezingC)       // compile error: type mismatch

而对于 == 、<、>= 比较一个有相同底层类型的数据,同样也不会成功

var c Celsius
var f Fahrenheit
fmt.Println(c == 0)          // "true"
fmt.Println(f >= 0)          // "true"
fmt.Println(c == f)          // compile error: type mismatch
fmt.Println(c == Celsius(f)) // "true"!

Celsius(f),类型转换操作,它并不会改变值,仅仅是改变值的类型而已

总结

  • 赋值运算, 注意 i++、 ++i、 v=i++
  • map 查找、类型断言或通道接收作为右值的情况
  • 可赋值性的规则
  • 类型转化

思考:
若是 func (c Celsius) String() string,这是声明形式的意义何在?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值