Рассмотрим следующий тест:
import (
"errors"
"fmt"
"testing"
)
func TestError(t *testing.T) {
err := &MyError{}
var target error
fmt.Println(errors.As(err, &target))
}
type MyError struct{}
func (err *MyError) Error() string {
return "oops!"
}
Запуск этого теста возвращает ошибку сборки second argument to errors.As should not be *error
.
Однако при запуске точно такого же кода в main
программа работает без проблем:
package main
import (
"errors"
"fmt"
)
func main() {
err := &MyError{}
var target error
fmt.Println(errors.As(err, &target))
}
type MyError struct{}
func (err *MyError) Error() string {
return "oops!"
}
Я вижу такое поведение в Go Playground и в моей локальной среде разработки, обе из которых используют Go 1.20.
Это ошибка в Go?
Я могу обойти ошибку сборки в тесте, создав тип Error
:
package main
import (
"errors"
"fmt"
"testing"
)
type Error error // <===== Add error type
func TestError(t *testing.T) {
err := &MyError{}
var target Error // <===== Use Error type
fmt.Println(errors.As(err, &target))
}
type MyError struct{}
func (err *MyError) Error() string {
return "oops!"
}
Об ошибке сообщает команда go vet
. Команда go test
автоматически запускает go vet
, чтобы сообщить о серьезных проблемах. Команда go build
не запускает команду go vet
.
Предупреждение не является ошибкой в Go.
Нет смысла вызывать errors.As с *error
в качестве второго аргумента, потому что вы уже знаете, что первый аргумент удовлетворяет интерфейсу error
. Вы почти наверняка делаете что-то не так.
В вашем тесте используется error
в качестве типа целевого значения. Таблица в стандартной библиотеке test хранит указатель на значение типа ошибки. Стандартная библиотека использует any
вместо error
, потому что указатель на ошибку не удовлетворяет интерфейсу error
. Следуйте шаблону в тесте стандартной библиотеки. В частности, сохраните указатель на целевое значение в таблице и передайте это значение непосредственно в errors.As (не берите адрес значения в таблице).
Ах, я упустил из виду, что
go test
работаетgo vet
, так что это должно быть ответом, почему я вижу это только сgo test
. Сказав это, причина, по которой я столкнулся с этим, заключается в том, что я искал, как использоватьerrors.As
в табличных тестах. Типичный пример того, что я пытаюсь сделать, есть в стандартной библиотеке. Обратите внимание, что они напечаталиtc.target
какany
, и мне казалось, что не должно быть причин, по которымtc.target
нельзя набирать какerror
и назначать разные типы ошибок в каждом тестовом примере.