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

时间:2019-11-15 10:18:16

标签: variables go types

我正在尝试初始化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))
}

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

为什么会发生?是不是和:=的分配相同?

Here there is the playground.

1 个答案:

答案 0 :(得分:5)

在此variable declaration中:

var err ErrNegativeSqrt = x

您为err明确指定了ErrNegativeSqrt类型,并尝试为其分配x,但是x属于float64类型,无法分配设置为ErrNegativeSqrt类型的值。 Assignability规则不适用,float64ErrNegativeSqrt是2种不同的不同类型(尽管后者以underlying type为前者,所以它们是{{3} })。

使用此convertible时:

err := ErrNegativeSqrt(x)

您将short variable declaration x显式地转换为ErrNegativeSqrt,因此x的类型将被推断为ErrNegativeSqrt

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

var err ErrNegativeSqrt = ErrNegativeSqrt(x)

或者简单地:

var err = ErrNegativeSqrt(x)

convert的缩写正是。

注释

如前所述,var err ErrNegativeSqrt = x无效,因为short variable declaration规则不适用:

  

如果满足以下条件之一,则值x可分配给类型T的{​​{3}}(“ x可分配给T”) :

     
      
  • x的类型与T相同。
  •   
  • x的类型VT具有相同的assignability,并且VT中的至少一个不是{{ 3}}类型。
  •   
  • T是接口类型,并且是x variable T
  •   
  • x是双向通道值,T是通道类型,x的类型VT具有相同的元素类型,并且在VT中至少有一个不是已定义的类型。
  •   
  • x是预先声明的标识符nil,而T是指针,函数,切片,映射,通道或接口类型。
  •   
  • x是类型为T的值的无类型underlying types defined
  •   

如您所见,第二条规则“几乎”涵盖了我们在此处要做的事情:

  

x的类型VT具有相同的基础类型,并且VT中的至少一个不是已定义类型

之所以“几乎”是因为ErrNegativeSqrtfloat64都被命名为(implements)类型。

当您这样做:

var err ErrNegativeSqrt = 1.0

之所以行之有效,是因为在这里您要分配一个 untyped constant 1.0,它可以在需要时采用所需的类型(如上述分配)。由于您要分配类型为err的{​​{1}},因此未类型化的常量ErrNegativeSqrt可以采用类型1.0(因为ErrNegativeSqrt的基础类型为{{1 }}和ErrNegativeSqrt是无类型的浮点常量)。这种情况恰好是最后一个可分配性规则:

  

float64是类型为1.0的值的无类型representable defined

如果愿意的话:

x

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

请阅读博客文章constant,详细了解常量在Go中的工作原理。