2015-03-17 3 views
0

Я пытаюсь понять концепцию интерфейса Go и создать следующий код:ссылка Интерфейс показывает странный выход

package main 

import "fmt" 

type Failer interface { 
    Error() string 
} 

type Succer interface { 
    Success() string 
} 

type Result interface { 
    Failer 
    Succer 
} 

type Fail struct{} 

func (*Fail) Error() string { 
    return "Error" 
} 

type Succ struct{} 

func (*Succ) Success() string { 
    return "Success" 
} 

type Combi struct{} 

func (*Combi) Error() string { 
    return "Error" 
} 

func (*Combi) Success() string { 
    return "Success" 
} 

func main() { 

    var r Result 
    var s Succer 

    c := &Combi{} 
    r = c 
    s = c 
    fmt.Println(r.Error()) 
    fmt.Println(s) 
} 

Как выход я получил

Error 
Error 

Почему? Я ожидаю как выходную ошибку и успех, потому что s это интерфейс типа Succer, в качестве строки нет возврата ошибки. И когда я изменяю основную функцию:

func main() { 

    var r Result 
    var s Succer 

    c := &Combi{} 
    r = c 
    s = c 

} 

компилятор жалуется

# command-line-arguments 
.\sample1.go:42: r declared and not used 
.\sample1.go:43: s declared and not used 

Почему? Я назначаю переменные r и s ссылку.

ответ

3

fmt.Println(s) печатает «Ошибка», потому что error это специальный обсаженным в fmt пакете

 switch v := p.arg.(type) { 
     case error: 
      handled = true 
      defer p.catchPanic(p.arg, verb) 
      p.printArg(v.Error(), verb, depth) 
      return 

     case Stringer: 
      handled = true 
      defer p.catchPanic(p.arg, verb) 
      p.printArg(v.String(), verb, depth) 
      return 
     } 
    } 

fmt пакета сначала проверяет, является ли объект является Formatter, GoStringer, error или Stringer, в таком порядке, чтобы получить значение для печати.

Что касается вашего последнего вопроса, вы должны использовать переменную, а не просто назначать ее. Печать их удаляет ошибку.

2

Что касается вашего первого вопроса - если вы добавите fmt.Println(reflect.TypeOf(s)) - вы увидите, что выход не Succer, а *main.Combi.

Теперь, поскольку он реализует интерфейс Error и имеет Error() string - Println думает, что это идет объект ошибки и печатает вывод его методы Error.

Изменение метода Error на все остальное остановит Println(s) от печати «Ошибка». Но он также не будет печатать «Успех».

0

В первом вопросе, если вы хотите напечатать успех с s вызова на success FUNC:

fmt.Println(s.Success()) 

О втором вопросе Go проверки составитель неиспользуемых переменных, поэтому назначать только без использования он показывает ошибку компиляции

Смежные вопросы