go - 为什么接受自定义结构来代替错误?

标签 go struct types error-handling

学习 Go 并引用 https://tour.golang.org/methods/20

package main

import (
    "fmt"
    "math"
)

type ErrNegativeSqrt float64 //This is the custom Struct

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

func Sqrt(x float64) (float64, error) {  // Is error a type ?
    if(x < 0){
        return x, ErrNegativeSqrt(x) //Q1) If error is a type, How come  ErrNegativeSqrt(x) is of type error?
    }       
    z := float64(1.5)
    val := float64(0)
    for {
        z = z - (z*z-x)/(2*z)
        if math.Abs(val-z) < 1e-10 {
            break
        }
        val = z
    }
    return val, nil
}

func main() {
    fmt.Println(Sqrt(2))
    fmt.Println(Sqrt(-2))
}

Q2) 为什么在 Error 方法中调用 fmt.Sprint(e) 会使程序陷入无限循环?

最佳答案

围棋interface很棘手。需要对它进行一些试验才能很好地了解如何使用它。这就是为什么您正在使用的教程让您使用它编写东西:您必须实际使用它一段时间才能了解如何使用它。 :-)

不过,值得在这里纠正一些细节:

type ErrNegativeSqrt float64 //This is the custom Struct


这不是 struct类型。 float64本身是一个预先声明的数字类型,as defined here in the Go reference :

A numeric type represents sets of integer or floating-point values. The predeclared architecture-independent numeric types are: [various entries snipped out here]

float64     the set of all IEEE-754 64-bit floating-point numbers


您的 type此处的声明创建了一个名为 ErrNegativeSqrt 的新类型有 float64作为其基础类型;见 the Types section .

A 类型——任何类型,无论是 struct与否——要么实现接口(interface)类型,要么不实现。接口(interface)类型很复杂。见 the Interface types section完整的图片。围棋error是一个预先声明的接口(interface)类型,由 the Errors section 定义:

The predeclared type error is defined as

type error interface {
    Error() string
}


这意味着,每当您定义自己的 UserT 类型时,如果您添加如下一行:
func (varname UserT) Error() string {
    // return some string here
}

您定义的类型 UserT 现在实现了错误接口(interface)。因此,您可以将 UserT 类型的任何值转换为 error通过简单的分配。见 the Assignability section , 包括:

A value x is assignable to a variable of type T... if one of the following conditions applies: [some bullet items snipped]

  • T is an interface type and x implements T


我们刚刚看到 error是一种接口(interface)类型。因此,如果某些情况需要 error 类型的变量,并且您有一些现有值 x类型 UserT在哪里 UserT有一个方法Error() string ,您可以分配该值 x进入 error 类型的变量.也就是说,给定 ErrNegativeSqrt像你一样设置,并且:
var x ErrNegativeSqrt
// set `x` to some valid value

// and:
var e error

然后:
e = x

有效并分配 x进入 e , 虽然 e 的类型本身是一个接口(interface)类型,而不是ErrNegativeSqrt .

当您填充 x 的值的副本时进入 e像这样,编译器实际上在 e 内部设置了两个东西.换句话说,e行为很像二元素数组,或 struct有两个字段,除了你不能用下标或 .field 访问这两个字段键入拼写。

这两个值之一——e 的前半部分的值—是 x的具体类型。这两个值中的另一个是 x的实际值,复制到 e 的另一半.

换句话说,编译器转向:
e = x

大致相当于:
e.value = x
e.type = ErrNegativeSqrt

再说一次,因为你实际上不能写 e.typee.value .编译器会自动为您进行两部分化。

You should have already seen how you can pick apart the two parts of things stored into e if necessary.通常没有必要,尤其是在界面设计良好的情况下。但是,在尝试了 #20 中的错误返回之后,值得回溯到巡回赛的这些早期部分。 .

关于go - 为什么接受自定义结构来代替错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59342836/

相关文章:

go - 我应该关心在我的 go 库中提供异步调用吗?

json - 解码后的 json 响应返回空结构

pointers - 测试嵌套结构中的 nil 值

android - 操作系统(iOS,Android,macOS,Windows)是否可以读取应用程序上载的数据类型(即使已加密)

python - 如何从字符串 'long' 创建一个 numpy dtype?

r - `1L` 和 `1` 之间有什么区别?

json - 将map转换为json会在golang中给出很多整数

go sql driver + context canceled 似乎是 "leak"goroutines?

go - Go 语言中更严格的编译选项

c++11 - 将 C++ 程序移植到 Rust : Of reinterpret_cast, 结构和蓝牙