@danforth

Как реализовать интерфейс в Go?

Всем привет!

Изучаю Go, добрался до интерфейсов, застрял на этом упражнении.

Задача такая: есть тип IPAddr основанный на базовом типе массив байт []byte. В этом типе будет хранится IP адрес.
Нужно реализовать интерфейс fmt.Stringer у которого есть один метод String() string. По финалу, IP должен выводится через точку, вот так: 8.8.8.8, у меня же в консоли (и в песочнице чуть ниже) все высыпает вот так [8 8 8 8]

Вот мой код (песочница):

package main

import "fmt"

type IPAddr [4]byte

// TODO: Add a "String() string" method to IPAddr.
func (i *IPAddr) String() string {
	return fmt.Sprintf("%d.%d.%d.%d", i[0], i[1], i[2], i[3])
}

func main() {
	hosts := map[string]IPAddr{
		"loopback":  {127, 0, 0, 1},
		"googleDNS": {8, 8, 8, 8},
	}
	for name, ip := range hosts {
		fmt.Printf("%v: %v\n", name, ip)
	}
}


Как же все таки реализовать интерфейс fmt.Stringer? Очевидно же, что у меня выводится просто %v, а не результат работы метода String()
  • Вопрос задан
  • 588 просмотров
Решения вопроса 1
evnuh
@evnuh
Поиск Гугл помог мне, впусти и ты его в свой дом
Вы реализовали интерфейс для типа "указатель на IPAddr", а распечатываете тип "IPAddr".

С этим возникает сложность из-за двойных стандартнов, принятых в Go, хотя и логичных. Запомните навсегда:

Pointer type can access the methods of its associated value type, but not vice versa. That is, a *Dog value can utilize the Speak method defined on Dog, but as we saw earlier, a Cat value cannot access the Speak method defined on *Cat.


То есть в вашем случае всё бы работало и при правильном совпадении типов И при неправильной, противоположной вашему коду ситуации - если бы вы реализовали интерфейс для самого типа, а пытались распечатать указатель на него.

Объясняется это просто - если метод реализован для указателя, он, скорее всего, может что-то менять в объекте по этому указателю, поэтому передавая объект по значению, а не по указателю - он бы менял не в самом объекте, а в его копии, которая бы делалась при передачи по значению. Это явно не то, чего ожидал писатель метода.
В обратном же случае, если метод определён для типа по значению, а не по указателю, очевидно что метод ничего в самом значении не меняет (если бы попытался, то менял бы опять же в копии значения). А раз он там ничего не меняет, можно смело передать наш объект под ссылкой.

Тут объясняется всё подробно: https://github.com/golang/go/wiki/MethodSets
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы