【问题标题】:Initialize a custom type doesn't work with var but works with :=初始化自定义类型不适用于 var 但适用于 :=
【发布时间】:2020-03-11 11:30:14
【问题描述】:

我正在尝试初始化一个 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.

【问题讨论】:

    标签: variables go types


    【解决方案1】:

    在这个variable declaration

    var err ErrNegativeSqrt = x
    

    您明确地给err 一个ErrNegativeSqrt 类型,并尝试将x 分配给它,但xfloat64 类型,它不能分配给ErrNegativeSqrt 类型的值。 Assignability 规则不适用,float64ErrNegativeSqrt 是 2 种不同的不同类型(尽管后者将前者作为其 underlying type,因此它们是彼此的 convertible)。

    当你使用这个short variable declaration:

    err := ErrNegativeSqrt(x)
    

    您明确地将convert x 转换为ErrNegativeSqrt,因此x 的类型将被推断为ErrNegativeSqrt

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

    var err ErrNegativeSqrt = ErrNegativeSqrt(x)
    

    或者简单地说:

    var err = ErrNegativeSqrt(x)
    

    这正是short variable declaration 的缩写形式。

    注意事项

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

    如果以下条件之一适用,则值 x 可分配给 T 类型的 variable(“x 可分配给 T”):

    • x 的类型与 T 相同。
    • x 的类型 VT 具有相同的 underlying types 并且至少 VT 之一不是 defined 类型。
    • T 是接口类型,x implements T
    • x是双向通道值,T是通道类型,x的类型VT具有相同的元素类型,并且VT至少有一个不是定义类型。
    • x 是预声明的标识符 nilT 是指针、函数、切片、映射、通道或接口类型。
    • x 是一个无类型的 constant representable,其值类型为 T

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

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

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

    当你这样做时:

    var err ErrNegativeSqrt = 1.0
    

    这是可行的,因为您在这里分配了一个 untyped constant 1.0,它可以在需要时采用所需的类型(如上面的分配)。由于您分配给ErrNegativeSqrt 类型的err,所以无类型常量1.0 可以采用ErrNegativeSqrt 类型(因为ErrNegativeSqrt 的基础类型是float64,而1.0 是一个无类型浮点型-点常数)。这种情况正是最后的可分配性规则:

    x 是一个无类型的constant representable,其值类型为T

    如果你愿意:

    var err ErrNegativeSqrt = float64(1.0) // FAIL!!
    

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

    阅读博文The Go Blog: Constants 了解更多关于常量如何在 Go 中工作的详细信息。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-30
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 2011-02-14
    • 1970-01-01
    相关资源
    最近更新 更多