Understanding the Error
Interface conversion errors occur when type assertions fail or types don't implement required interfaces:
``` panic: interface conversion: interface {} is nil, not string
panic: interface conversion: interface {} is int, not string
./main.go:15:10: cannot use &MyStruct literal (type *MyStruct) as type MyInterface: *MyStruct does not implement MyInterface (missing Method method) ```
Common Scenarios and Solutions
Scenario 1: Type Assertion on Nil Interface
Problem code:
``go
func main() {
var i interface{} // nil interface
s := i.(string) // panic: interface conversion: interface {} is nil, not string
fmt.Println(s)
}
Solution - Use comma-ok idiom: ```go func main() { var i interface{}
s, ok := i.(string) if !ok { fmt.Println("Interface is not a string or is nil") return } fmt.Println(s) } ```
Safe assertion helper:
``go
func safeString(i interface{}) string {
if i == nil {
return ""
}
s, ok := i.(string)
if !ok {
return ""
}
return s
}
Scenario 2: Wrong Type in Assertion
Problem code: ```go func process(data interface{}) { s := data.(string) // panic if data is not a string fmt.Println(s) }
func main() { process(42) // panic: interface conversion: interface {} is int, not string } ```
Solution - Type switch:
``go
func process(data interface{}) {
switch v := data.(type) {
case string:
fmt.Println("String:", v)
case int:
fmt.Println("Int:", v)
case float64:
fmt.Println("Float:", v)
case bool:
fmt.Println("Bool:", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}
Scenario 3: Interface Not Implemented
Problem code: ```go type Reader interface { Read([]byte) (int, error) }
type FileReader struct { path string }
func (f FileReader) Read(p []byte) (int, error) { // implementation return 0, nil }
func (f FileReader) Close() error { return nil }
func useReader(r Reader) {}
func useReadCloser(rc interface { Reader Close() error }) {}
func main() { f := FileReader{path: "/tmp/file"} useReader(f) // Works: FileReader implements Reader
fr := &FileReader{path: "/tmp/file"} useReader(fr) // Works: *FileReader also implements Reader
useReadCloser(f) // Works useReadCloser(fr) // Works } ```
When methods require pointer receiver: ```go type Writer interface { Write([]byte) (int, error) }
type Buffer struct { data []byte }
func (b *Buffer) Write(p []byte) (int, error) { b.data = append(b.data, p...) return len(p), nil }
func main() { var b Buffer // Value, not pointer var w Writer = b // Error: Buffer does not implement Writer
var w Writer = &b // Works: *Buffer implements Writer } ```
Why: Methods with pointer receivers are only accessible on pointers. Buffer doesn't have Write, only *Buffer does.
Scenario 4: Embedded Interface Conversion
Problem code: ```go type Reader interface { Read([]byte) (int, error) }
type Writer interface { Write([]byte) (int, error) }
type ReadWriter interface { Reader Writer }
func main() { var r Reader = getReader() rw := r.(ReadWriter) // panic: interface conversion: Reader does not contain Write } ```
Solution - Check before assertion: ```go func main() { var r Reader = getReader()
// Safe check if rw, ok := r.(ReadWriter); ok { rw.Write([]byte("hello")) } else { fmt.Println("Reader does not implement ReadWriter") } } ```
Scenario 5: Nil Inside Non-nil Interface
This is a subtle Go gotcha:
```go type MyInterface interface { Method() }
type MyStruct struct{}
func (m *MyStruct) Method() {}
func main() { var s *MyStruct = nil // nil pointer var i MyInterface = s // i is NOT nil!
fmt.Println(i == nil) // false! i.Method() // Works! Method called on nil receiver } ```
Explanation: An interface has two components: type and value. i has type *MyStruct and value nil, so i itself is not nil.
Solution - Handle nil interface correctly: ```go func isInterfaceNil(i interface{}) bool { if i == nil { return true } v := reflect.ValueOf(i) switch v.Kind() { case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan, reflect.Func, reflect.Interface: return v.IsNil() } return false }
func main() { var s *MyStruct = nil var i MyInterface = s
if isInterfaceNil(i) { fmt.Println("Interface contains nil value") } } ```
Safe Interface Patterns
Pattern 1: Defensive Function Parameters
```go func processString(s interface{}) (string, error) { if s == nil { return "", errors.New("nil value") }
str, ok := s.(string) if !ok { return "", fmt.Errorf("expected string, got %T", s) } return str, nil } ```
Pattern 2: Interface Guard at Compile Time
```go type MyInterface interface { DoSomething() }
// Compile-time check var _ MyInterface = (*MyStruct)(nil)
type MyStruct struct{}
func (m *MyStruct) DoSomething() {} ```
Pattern 3: Optional Interface Check
```go type Writer interface { Write([]byte) (int, error) }
type Flusher interface { Flush() error }
func writeAll(w Writer, data []byte) error { _, err := w.Write(data) if err != nil { return err }
// Optional: check if writer can flush if f, ok := w.(Flusher); ok { return f.Flush() } return nil } ```
Pattern 4: Unwrap for Errors
```go func main() { var err error
// Check for specific error type var pathErr *os.PathError if errors.As(err, &pathErr) { fmt.Printf("Path error: %s\n", pathErr.Path) }
// Check for specific error value if errors.Is(err, os.ErrNotExist) { fmt.Println("File does not exist") } } ```
Debugging Interface Issues
Print Type Information
```go func debugInterface(i interface{}) { if i == nil { fmt.Println("Interface is nil") return }
t := reflect.TypeOf(i) v := reflect.ValueOf(i)
fmt.Printf("Type: %v\n", t) fmt.Printf("Kind: %v\n", t.Kind()) fmt.Printf("Value: %v\n", v)
if t.Kind() == reflect.Ptr { fmt.Printf("Points to: %v\n", v.Elem()) }
// List methods fmt.Println("Methods:") for j := 0; j < t.NumMethod(); j++ { m := t.Method(j) fmt.Printf(" - %s\n", m.Name) } } ```
Check Interface Satisfaction
```go func implements(i interface{}, targetInterface interface{}) bool { targetType := reflect.TypeOf(targetInterface).Elem() actualType := reflect.TypeOf(i)
if actualType == nil { return false }
return actualType.Implements(targetType) }
// Usage var r io.Reader fmt.Println(implements(&bytes.Buffer{}, (*io.Reader)(nil))) // true ```
Verification
```bash # Compile and check go build ./...
# Run tests go test ./...
# Use static analysis go vet ./... staticcheck ./... ```