I'd like to understand why one would create a type for handling errors in Go and how you decide what underlying type it should have

Viewed 637

I'm working through A Tour of Go - Exercise: Errors. It holds my hand as I add error handling to a square root function.

Here is my solution:

package main

import (
    "fmt"
    "math"
)

type ErrNegativeSqrt float64

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

func Sqrt(x float64) (float64, error) {
    z := 1.0
    margin := 0.00000000000001
    for {
        if x < 0 {
            return 0, ErrNegativeSqrt(x)
        }
        previousZ := z
        z = z - (z*z-x)/(2*z)
        if math.Abs(previousZ-z) < margin {
            fmt.Println(previousZ, "-", z, "=", previousZ-z)
            break
        }
    }
    fmt.Println("math.Sqrt:", math.Sqrt(x))
    return z, nil
}

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

I am having trouble understanding the line:

type ErrNegativeSqrt float64

I have two questions:

  1. Why is the underlying type of ErrNegativeSqrt "float64" and not "error"?

and

  1. Why create a type in the first place? Why do we create an error type and add a method to it instead of just having a free-standing function?

I'm a beginner at Go and I'd like to understand. Thank you so much.

3 Answers
Related