开发者

Go习惯用法(多值赋值短变量声明赋值简写模式)基础实例

开发者 https://www.devze.com 2024-01-19 10:29 出处:网络 作者: 程序员的自我进化
目录1. 多值赋值2. 短变量的声明编程和赋值3. 简写模式4. 多值返回函数5. comma,ok 表达式6. 传值规则1. 多值赋值
目录
  • 1. 多值赋值
  • 2. 短变量的声明编程和赋值
  • 3. 简写模式
  • 4. 多值返回函数
  • 5. comma,ok 表达式
  • 6. 传值规则

1. 多值赋值

可以一次性声明多个变量,并可以在声明时赋值,而且可以省略类型,但必须遵守一定的规则要求。

package main 
import "fmt"
func main() {
    var x, y int  // 相同类型变量可以在末尾带上类型
    var a, b int = 1, 2
    var c, d = 3, 4 // 不带类型时,编译器自动推断
    var (  // 不同类型变量声明和隐式初始化
        e int
        f string
        )
    var g int, e int = 6, 7  // 多赋值语句中每个变量后面不能都带上类型
    fmt.Println("x ", x)
    fmt.Println("y ", y)
    fmt.Println("a ", a)
    fmt.Println("b ", b)
    fmt.Println("c ", c)
    fmt.Println("d ", d)
    fmt.Println("e ", e)
    fmt.Println("f ", f)
}

有如下错误:

.\main.go:14:14: syntax error: unexpected comma at end of statement

2. 短变量的声明和赋值

Go  语言的语法允许多值短变量声明和赋值的多个变量中,只要有一个是新变量就可以使用 := 进行赋值。

也就是说,在多值短变量的声明和赋值时, 至少有一个变量是新创建的局部变量,其他的变量可以复用以前的变量,不是新创建的变量执行的仅仅是赋值。

package main 

import "fmt"

func main() {
    var a int = 0
    var b int = 0
    a, b := 1, 2
    fmt.Println("a ", a)
    fmt.Println("b ", b)
}

会有以下错误:

 .\main.go:8:10: no new variables on left side of :=

要想通过编译, a, b := 1, 2 至少一个变量是新定义的局部变量,如果在赋值语句 a, b := 1, 2  中已经存在一个局部变量 a ,则赋值语句不会创建新的变量 a , 而是使用 1 赋值给已经声明的局部变量。但是会创建新的变量 b 并给其赋值。

赋值操作符 &www.devze.comnbsp;和 :=  的区别:

  •  不会声明并创建新变量,而是在当前赋值语句所在的作用域由内向外逐层去搜寻变量,如果没有搜索到相同的变量名,则报编译错误。

  • :=  必须出现在函数或者类型方法内部。

  • :=  至少要创建一个局部变量并初始化。

多值短变量声明赋值 := 的最佳使用场景是在错误处理上。例如:

a, err := f()
if err ! = n编程客栈il {
    // do something
}
// 此时 err 可以是已存在的 err 变量,只是重新赋值了
b, err := g()

3. 简写模式

Go  语言很多重复的引用或声明可以用 ()  进行简写。

import 多个包;

// 推荐写法
import (
    "os"
    "fmt"
)
// 不推荐写法
import "os"
import "fmt"

多个变量声明;

包中多个相关全局变量声明时,建议使用 () 进行合并声明

// 推荐写法
var (
    uploadStatus bool
    downStatus bool
)
// 不推荐写法
var uploadStatus bool
var uploadStatus bool

4. 多值返回函数

多值返回函数里如果有 error  或 bool  类型的返回值,则应该将 error 和 bool 作为最后一个返回值。这是一种编程风格,没有对错。

buffer.go:107: func (b *Buffer) tryGrowByReslice(n int) (int, bool) {
buffer.go:335: func (b *Buffer) ReadByte() (byte , error) {

5. comma,ok 表达式

常见的几个 comma, ok 表达式用法有以下几种情况:

获取 map 值

获取 map 中不存在键的值不会发生异常,而是会返回值类型的零值,如果想确定 map 中是否存在某个 key,则可以使用获取 map 值的 comma, ojavascriptk 语法。示例如下:

m := make(map[string] string)
v, ok := m["camera"]
if ok {
    Println("camera exist")
} else {
    Println("camera not exist")
}

读取 chan 值

读取已经关闭的通道不会阻塞,也不会引起 panic, 而是一直返回该通道的零值,判断通道关闭有两种方法,一种是 comma, ok 表达式;另一种是通过 range 循环迭代。

c := make(chan int)
go func() {
    c <- 1
    c <- 2
    close(c)
}()
for {
    v, ok := <- c
    if ok {
        Println("v exist")
    } else {
        Println("v not exist")
    }
}
for v := range c {
    Println(v)
}
  • 类型断言

如果 map 查找、类型断言或通道接收出现在赋值语句的右边,它们都可能会产生两个结果,有一个额外的布尔结果表示操作是否成功:

v, ok = m[key]             // map lookup
v, ok = x.(T)              // type assertion
v, ok = &lt;-ch               // channel receive

注意:map 查找、类型断言或通道接收出现在赋值语句的右边时,并不一定是产生两个结果,也可能只产生一个结果。对于只产生一个结果的情形, map 查找失败时会返回零值,类型断言失败时会发生运行时 panic 异常,通道接收失败时会返回零值(阻塞不算是失败)。例如下面的例子:

v = m[key]                // map查找,失败时返回零值
v = x.(T)                 // type断言,失败时panic异常
v = &lt;-ch                  // 管道接收,失败时返回零值(阻塞不算是失败)
_, ok = m[key]            // map返回2个值
_, ok = mm[""], false     // map返回1个值
_ = mm[""]                // map返回1个值

和变量声明一样,我们可以用下划线空白标识符_来丢弃不需要的值。

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

6. 传值规则

Go  只有一种参数传递规则,那就是值拷贝,这种规则包括两种含义:

  • 函数参数传递时使用的是值拷贝。

  • 实例赋值给接口变量,接口对实例的引用是值拷贝。

有时在明明是值拷贝的地方,结果却修改了变量的内容,有以下两种情况:

  • 直接传递的是指针。指针传递同样是值拷贝,但指针和指针副本的值指向的地址是同一个地方,所以能修改实参值。

  • 参数是复合数据类型,这些复合数据类型内部有指针类型的元素,此时参数的值拷贝并不影响指针的指向。

Go  复合类型中 chan  、 map  、 slice  、 interface  内部都是通过指针指向具体的数据,这些类型的变量在作为函数参数传递时,实际上相当于指针的副本。

package main
import "fmt"
func main() {
    var x, y int = 3, 5
    fmt.Printf("befor swap x is %d\n", x)
    fmt.Printf("befor swapy is %d\n", y)
    x, y = swap_value(x, y)
    fmt.Printf("after swap x is %d\n", x)
    fmt.Printf("after swap y is %d\n", y)
    x, y = swap_reference(&x, &y)
    fmt.Printf("after swap_reference x is %d\n", x)
    fmt.Printf("after swap_reference y is %d\n", y)
}
func swap_value(x int, y int) (int, int) {
    var tmp int
    tmp = x
    x = y
    y = tmp
    return x, y
}
func swap_reference(x *int, y *int) (int, int) {
    var tmp int
    tmp = *x
    *x = *y
    *y = tmp
    return *x, *y
}

输出:

befor swap x is 3

befor swapy is 5

after swap x is 5

after swap y is 3

after swap_reference x is 3

after swap_reference y is 5

以上就是Go习惯用法(多值赋值短变量声明赋值简写模式)基础实例的详细内容,更多关于Go多值赋值短变量声明的资料请关注编程客栈(www.devze.com)其它相关文章!

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号