4.赋值与类型

元组赋值

1
2
3
4
5
a,b := b,a   								// 实现变量交换
i, j, k = 2, 3, 5  					// 赋值
q, w, e = 2, '3', true  		// 不同类型赋值
_, err = io.Copy(dst, src)  // 丢弃字节数
_, ok = x.(T)               // 只检测类型,忽略具体值

最大公约数

1
2
3
4
5
6
func gcd(x, y int) int {
    for y != 0 {
        x, y = y, x%y
    }
    return x
}

斐波那契数列

1
2
3
4
5
6
7
func fib(n int) int {
    x, y := 0, 1
    for i := 0; i < n; i++ {
        x, y = y, x+y
    }
    return x
}
1
2
3
4
5
6
v = m[key]                // map查找,失败时返回零值
v = x.(T)                 // type断言,失败时panic异常
v = <-ch                  // 管道接收,失败时返回零值(阻塞不算是失败)
v, ok = m[key]            // map lookup
v, ok = x.(T)             // type assertion
v, ok = <-ch              // channel receive

目前我们已经讨论过的类型,它的规则是简单的:类型必须完全匹配,nil可以赋值给任何指针或引用类型的变量。

对于两个值是否可以用==!=进行相等比较的能力也和可赋值能力有关系:对于任何类型的值的相等比较,第二个值必须是对第一个值类型对应的变量是可赋值的,反之亦然。

类型

1
type 类型名字 底层类型

类型声明语句一般出现在包一级,因此如果新创建的类型名字的首字符大写,则在包外部也可以使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// Package tempconv performs Celsius and Fahrenheit temperature computations.
package tempconv

import "fmt"

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

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

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

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

它们是不同的数据类型,因此它们不可以被相互比较或混在一个表达式运算。

只有当两个类型的底层基础类型相同时,才允许类型强制转换

在任何情况下,运行时不会发生转换失败的错误(译注: 错误只会发生在编译阶段)

整数除以整数,地板除法,即结果仅保留整数

任意参数带小数点,则结果就是浮点类型

内建类型

内建类型

复数

complex64和complex128,分别对应float32和float64两种浮点数精度。内置的complex函数用于构建复数,内建的real和imag函数分别返回复数的实部和虚部:

1
2
3
4
5
var x complex128 = complex(1, 2) // 1+2i
var y complex128 = complex(3, 4) // 3+4i
fmt.Println(x*y)                 // "(-5+10i)"
fmt.Println(real(x*y))           // "-5"
fmt.Println(imag(x*y))           // "10"

格式化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
%c  # 字符
%q  # 单引号字符
%d  # 数字
%o  #八进制
%x  # 十六进制
%g 	# 紧凑形式浮点 , 建议使用 %f
%f  # 浮点, 可以 %8.3f, 整数部分 8 位, 小数点后 3 位
%e  # 带指数
%+v # 结构体名,参数名和值
%#v # 包名,结构体名,参数名和值

1
2
3
fmt.Printf("%d %[1]x %#[1]x %#[1]X\n", x)
// Output:
// 3735928559 deadbeef 0xdeadbeef 0XDEADBEEF

%之后的[1]副词告诉Printf函数再次使用第一个操作数。第二,%后的#副词告诉Printf在用%o、%x或%X输出时生成0、0x或0X前缀。

指令修饰符

  • % d 如果输出的数字为负,则在其前面加上一个减号"-"。如果输出的是整数,则在前面加一个空格。使用 %x 或者 %X 格式化指令输出时,会在结果之间添加一个空格。例如 fmt.Printf("% X", “实”)输出 E5 AE 9E
    • %#o 以 0 开始的八进制数据
    • %#x 以 0x 开始的十六进制数据
  • + 在数值前面输出+号或者-号,为字符串输出 ASCII 字符(非 ASCII 字符会被转义),为结构体输出其字段名
  • - 将值向左对齐(默认右对齐)
  • 0 以数字 0 进行填充

常量

常量表达式的值在编译期计算,而不是在运行期。每种常量的潜在类型都是基础类型:boolean、string或数字。指针 , 结构体 , 接口 都不是常量

1
2
3
4
5
6
7
const err = errors.New("error")  // ❌

const filename string = "abc.txt"
// 或者
const (
  filename string = "t.txt"
)

Go 语言预定义了 true , false iota 常量

iota 常量生成器

const关键字出现时被重置为 0,在下一个 const 出现之前,每出现一次 iota,其所代表的数字自动加 1。

1
2
3
4
5
6
7
const (
    a = iota  //a == 0
    b = iota  //b ==1
    c = iota  //c == 2
)

const d = iota //d==0,因为const的出现,iota被重置为0

看题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const (
	c = 0
	d = iota    // 1
	e           // 2
	f = "hello" // hello
	// nothing
	g                 // hello
	h    = iota       // 5
	i                 // 6
	j    = 0          // 0
	k                 // 0
	l, m = iota, iota // 9 9
	n, o              // 10 10

	p = iota + 1                  // iota+1 =   12
	q                             // iota+1 = 13
	_                             // iota+1 = 14
	r = iota * iota               // iota = 14       14*14=196
	s                             //  iota*iota =  15*15
	t = r                         // 建议不要这么做
	u                             //
	v = 1 << iota                 // 1 << 18
	w                             // 1 << 19
	x               = iota * 0.01 // 0.20
	y float32       = iota * 0.01 // 0.21
	z                             // 0.22
)
  1. 不同 const 定义块互不干扰
  2. 所有注释行和空行全部忽略( _ 是忽略变量, 但是算做一行)
  3. 没有表达式的常量定义复用上一行
  4. 从第一行开始, iota 逐行+1, 哪怕第一行不是 iota, 也从第一行算
  5. 替换所有 iota

如果是批量声明的常量,除了第一个外其它的常量右边的初始化表达式都可以省略,如果省略初始化表达式则表示使用前面常量的初始化表达式写法,对应的常量类型也一样的。

1
2
3
4
5
6
7
8
const (
    a = 1
    b
    c = 2
    d
)

fmt.Println(a, b, c, d) // "1 1 2 2"

Go语言的常量有个不同寻常之处。虽然一个常量可以有任意一个确定的基础类型,例如int或float64

编译器为这些没有明确基础类型的数字常量提供比基础类型更高精度的算术运算;你可以认为至少有256bit的运算精度。这里有六种未明确类型的常量类型,分别是无类型的布尔型、无类型的整数、无类型的字符、无类型的浮点数、无类型的复数、无类型的字符串。

只有常量可以是无类型的。当一个无类型的常量被赋值给一个变量的时候,就像下面的第一行语句,或者出现在有明确类型的变量声明的右边,如下面的其余三行语句,无类型的常量将会被隐式转换为对应的类型,如果转换合法的话。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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')
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 		a := 12   // 默认长度 8,即类型  int64
    fmt.Println("length of a: ", unsafe.Sizeof(a))
    var b int = 12 // 根据机器自动,32 or 64
    fmt.Println("length of b(int): ", unsafe.Sizeof(b))
    var c int8 = 12 // 0-255  1 个字节
    fmt.Println("length of c(int8): ", unsafe.Sizeof(c))
    var d int16 = 12  // 0-65535  2 个字节
    fmt.Println("length of d(int16): ", unsafe.Sizeof(d))
    var e int32 = 12  //    四个字节
    fmt.Println("length of e(int32): ", unsafe.Sizeof(e))
    var f int64 = 12
    fmt.Println("length of f(int64): ", unsafe.Sizeof(f))

Licensed under CC BY-NC-SA 4.0
本文阅读量 次, 总访问量 ,总访客数
Built with Hugo .   Theme Stack designed by Jimmy