Почему я получаю ошибку invalid operation: err (variable of type Error) is not an interface при проверке типа переменной?

Ссылка скопирована
Go
1 ответ

Я пытаюсь проверить, реализует ли переменная err интерфейс error.
В данном коде видно что err является экземпляром MyError, который реализует метод Error.
Насколько я понимаю реализация метода Error является достаточным для того чтобы имплементировать интерфейс в Go.
Скажите почему я получаю ошибку?

package main  import "fmt"  type MyError struct { 	Message string }  func (e MyError) Error() string { 	return e.Message }  func main() { 	err := MyError{"Something went wrong"}  	// Проверяем, реализует ли err интерфейс error 	if _, ok := err.(error); ok { 		fmt.Println("err реализует интерфейс error") 	} else { 		fmt.Println("err НЕ реализует интерфейс error") 	} }

package main import "fmt" type MyError struct { Message string } func (e MyError) Error() string { return e.Message } func main() { err := MyError{"Something went wrong"} // Проверяем, реализует ли err интерфейс error if _, ok := err.(error); ok { fmt.Println("err реализует интерфейс error") } else { fmt.Println("err НЕ реализует интерфейс error") } }

Консольный вывод:

vlad@DESKTOP:~/go/src/project$ go run cmd/structure/main.go # command-line-arguments                                                                           cmd/structure/main.go:17:14: invalid operation: err (variable of type MyError) is not an interface

vlad@DESKTOP:~/go/src/project$ go run cmd/structure/main.go # command-line-arguments cmd/structure/main.go:17:14: invalid operation: err (variable of type MyError) is not an interface

https://go.dev/play/p/AN2_V0ozTpL

Дополнительно:

https://go.dev/play/p/eDi3J3Zzcdg

package main  import "fmt"  type MyError struct { 	Message string }  func (e MyError) Error() string { 	return e.Message }  func (e MyError) Smth() { }  type SomeInterface interface { 	Smth() }  func main() { 	var err SomeInterface 	err = MyError{"Something went wrong"}  	// Проверяем, реализует ли err интерфейс error 	if _, ok := err.(error); ok { 		fmt.Println("err реализует интерфейс error") 	} else { 		fmt.Println("err НЕ реализует интерфейс error") 	} }

package main import "fmt" type MyError struct { Message string } func (e MyError) Error() string { return e.Message } func (e MyError) Smth() { } type SomeInterface interface { Smth() } func main() { var err SomeInterface err = MyError{"Something went wrong"} // Проверяем, реализует ли err интерфейс error if _, ok := err.(error); ok { fmt.Println("err реализует интерфейс error") } else { fmt.Println("err НЕ реализует интерфейс error") } }

У вас получилось, что тип переменной err это структура, но нужно чтобы тип был каким-нибудь интерфейсом.

В моем примере я создал интерфейс SomeInterface и добавил вашему типу метод, чтобы он этому интерфейсу удовлетворял. Теперь данный ассершн имеет смысл.

P.S. С пустым интерфейсом тоже работать будет https://go.dev/play/p/Yz0M1Wzopua

Я полностью присоединюсь к ответу выше, просто хочу дополнить.

Замечу, что вы проверяете не то, что нужно, шиворот-навыворот. Проверять при приведении типов лучше конкретные типы. Т.е. мы получаем из функции ошибку в виде интерфейса error, а уже в проверке проверяем её на наш кастомный тип MyError. Поэтому желательно (не обязательно) не проверять переменную ошибки в той же функции, где вы её создали, а возвращать откуда-то и уже тогда проверять на ошибку.

К тому же, если у вас вопросы по этой теме, я настоятельно хочу порекомендовать правильно использовать кастомные типы ошибок, и даже если указатель на ваш кастомный тип ошиьбки равен nil, то ни в коем случае не возвращайте сам этот указатель, а возвращайте буквально nil. Так вы избавитесь от тысяч выстрелов себе в ногу.

package main  import ( 	"fmt" )  type MyError struct { 	Message string }  func (e MyError) Error() string { 	return e.Message }  func main() { 	// Возвращаем из функции нашу кастомную ошибку, но в виде интерфейса error 	err := foo()  	if err == nil { 		fmt.Println("Нет ошибки") 	// И теперь тут приводим error к нашему типу MyError и проверяем 	} else if myErr, ok := err.(MyError); ok { 		fmt.Printf("Ура! Нужный нам тип ошибки: %vn", myErr.Message) 	} else { 		fmt.Println("Какой-то другой тип ошибки:", err) 	}  	// Проверка одной из "подстав" Go  	err = bad() 	if err != nil { 		fmt.Println("Упс... Как так... Не nil...") 	} else { 		fmt.Println("Должно вывестись это, но не выводится...") 	}  	err = good() 	if err != nil { 		fmt.Println("Это не должно выводиться, всё верно.") 	} else { 		fmt.Println("Ошибки нет, всё верно.") 	} }  func foo() error { 	err := MyError{"Ой! Ошибка MyError!"} 	// err := fmt.Errorf("Ой! Обычная ошибка!") 	// var err error = nil 	return err }  func bad() error { 	var p *MyError = nil // Вроде же nil, но не работает.... 	// p = &MyError{"Ой!"} // Пробуем создать ошибку, и всё работает.  	if p == nil { 		fmt.Println("Ну nil же-ж... Должно же-ж работать", p) 	}  	return p }  func good() error { 	// return MyError{"Ой!"}          // Буквально пишем "nil", никаких указателей, которые равны nil, это прямой выстрел в ногу 	return nil }

package main import ( "fmt" ) type MyError struct { Message string } func (e MyError) Error() string { return e.Message } func main() { // Возвращаем из функции нашу кастомную ошибку, но в виде интерфейса error err := foo() if err == nil { fmt.Println("Нет ошибки") // И теперь тут приводим error к нашему типу MyError и проверяем } else if myErr, ok := err.(MyError); ok { fmt.Printf("Ура! Нужный нам тип ошибки: %vn", myErr.Message) } else { fmt.Println("Какой-то другой тип ошибки:", err) } // Проверка одной из "подстав" Go err = bad() if err != nil { fmt.Println("Упс... Как так... Не nil...") } else { fmt.Println("Должно вывестись это, но не выводится...") } err = good() if err != nil { fmt.Println("Это не должно выводиться, всё верно.") } else { fmt.Println("Ошибки нет, всё верно.") } } func foo() error { err := MyError{"Ой! Ошибка MyError!"} // err := fmt.Errorf("Ой! Обычная ошибка!") // var err error = nil return err } func bad() error { var p *MyError = nil // Вроде же nil, но не работает.... // p = &MyError{"Ой!"} // Пробуем создать ошибку, и всё работает. if p == nil { fmt.Println("Ну nil же-ж... Должно же-ж работать", p) } return p } func good() error { // return MyError{"Ой!"} // Буквально пишем "nil", никаких указателей, которые равны nil, это прямой выстрел в ногу return nil }

https://go.dev/play/p/2YcWcH9oqel

Нужно решить такую задачу?

Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

Заказать помощь
Лучший ответ
1
Дмитрий К. Ответ

Ошибка "invalid operation: err (variable of type Error) is not an interface" возникает, когда вы пытаетесь использовать оператор проверки типа переменной для переменной, которая не является интерфейсом.

В языке программирования PHP оператор проверки типа переменной (instanceof) используется для определения, принадлежит ли объект к определенному классу или интерфейсу. Однако, если вы пытаетесь использовать этот оператор для переменной типа Error, который не является интерфейсом, то возникает ошибка "invalid operation: err (variable of type Error) is not an interface".

Чтобы исправить эту ошибку, вам необходимо использовать другой способ проверки типа переменной для типа данных Error. Вы можете использовать функцию is_a(), которая проверяет, является ли объект экземпляром класса или интерфейса. Например:

$error = new Error();
if (is_a($error, 'Error')) {
    echo 'This is an instance of Error class';
} else {
    echo 'This is not an instance of Error class';
}

$error = new Error(); if (is_a($error, 'Error')) { echo 'This is an instance of Error class'; } else { echo 'This is not an instance of Error class'; }

Таким образом, используя функцию is_a() вместо оператора instanceof, вы сможете успешно проверить тип переменной типа Error без возникновения ошибки "invalid operation: err (variable of type Error) is not an interface".

Другие ответы (0)

Пока нет других ответов. Будьте первым, кто поможет автору.

Ответить на вопрос

комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может быть интересно