初始化自定义类型不适用于var,但适用于:=

Cir*_*i94 1 variables types go

我正在尝试初始化ErrNegativeSqrt,它是一个自定义的float64类型,但是如果我这样做,var它将无法正常工作。

看一下func Sqrt(x float64) (float64, error)

package main

import (
    "fmt"
)

type ErrNegativeSqrt float64

func (e *ErrNegativeSqrt) Error() string {
    return fmt.Sprint("cannot Sqrt negative number: %f", float64(*e))
}

func Sqrt(x float64) (float64, error) {
    if x < 0 {
        var err ErrNegativeSqrt = x
        // This works: err := ErrNegativeSqrt(x)
        return x, &err
    }

    z := x / 2
    i := 1

    for prev_z := 0.0; z != prev_z && Abs(z-prev_z) > 0.000000000000001; i++ {
        prev_z = z
        z -= (z*z - x) / (2 * z)
    }

    return z, nil
}

func Abs(x float64) float64 {
    if x < 0 {
        x = -x
    }
    return x
}

func main() {
    fmt.Println(Sqrt(2))
    fmt.Println(Sqrt(-2))
}
Run Code Online (Sandbox Code Playgroud)

错误是: ./prog.go:15:7: cannot use x (type float64) as type ErrNegativeSqrt in assignment

为什么会发生?与分配作业不一样:=吗?

这里有游乐场。

icz*_*cza 5

在此变量声明中

var err ErrNegativeSqrt = x
Run Code Online (Sandbox Code Playgroud)

您显式地指定err的类型ErrNegativeSqrt,然后尝试分配x给它,但是该x类型的类型float64不能分配给type的值ErrNegativeSqrt可分配性规则不适用,float64并且ErrNegativeSqrt是2种不同的不同类型(尽管后者具有前者作为其基础类型,所以它们可以相互转换)。

使用此简短变量声明时

err := ErrNegativeSqrt(x)
Run Code Online (Sandbox Code Playgroud)

您显式转换 xErrNegativeSqrt,因此x类型将被推断为ErrNegativeSqrt

使用var关键字时,您可以这样做:

var err ErrNegativeSqrt = ErrNegativeSqrt(x)
Run Code Online (Sandbox Code Playgroud)

或者简单地:

var err = ErrNegativeSqrt(x)
Run Code Online (Sandbox Code Playgroud)

这正是short变量声明的缩写形式。

笔记

如前所述,var err ErrNegativeSqrt = x无效是因为可分配性规则不适用:

如果满足以下条件之一,则可将值x分配给类型的变量T(“ x可分配给T”):

  • x的类型与相同T
  • x的类型,V并且T具有相同的基础类型,并且至少是定义的类型之一VT不是定义的类型。
  • T是接口类型并x 实现 T
  • x是双向通道值,T是通道类型,x的类型,V并且T具有相同的元素类型,并且至少是定义的类型之一VT不是定义的类型。
  • x是预先声明的标识符,nil并且T是指针,函数,切片,映射,通道或接口类型。
  • x是可由type值表示的无类型常量T

如您所见,第二条规则“几乎”涵盖了我们要在此处执行的操作:

x的类型,V并且T具有相同的基础类型,并且至少是一种VT不是定义的类型

之所以只是“几乎”,是因为ErrNegativeSqrtfloat64都被命名(定义)了。

当您这样做时:

var err ErrNegativeSqrt = 1.0
Run Code Online (Sandbox Code Playgroud)

之所以有效,是因为您在这里分配一个无类型的 常量 1.0,该常量可以在需要时采用所需的类型(如上述分配中所示)。由于您要分配给errtype ErrNegativeSqrt,因此无类型的常量1.0可以采用该类型ErrNegativeSqrt(因为ErrNegativeSqrt的基础类型为float64,并且1.0是无类型的浮点常量)。这种情况恰好是最后一个可分配性规则:

x是可由type值表示的无类型常量T

如果您愿意:

var err ErrNegativeSqrt = float64(1.0) // FAIL!!
Run Code Online (Sandbox Code Playgroud)

这将再次失败,就像您在问题中的示例一样,因为在这里我们使用的类型化常量不能任意更改类型,没有可分配性规则允许这样做。

阅读博客文章The Go Blog:Constants,了解更多详细信息。