Ценность получения

Головоломка

Как вы думаете, что напечатает следующая программа?

package main
import (
    "fmt"
)
type Coordinate struct {
    Lat float64
    Lng float64
}
func (c *Coordinate) String() string {
    return fmt.Sprintf("%f/%f", c.Lat, c.Lng)
}
func main() {
    c := Coordinate{32.5253837, 34.9408283}
    fmt.Println(c)
}

Эта программа напечатает: {32.5253837 34.9408283}.

Ждать! Что? Coordinate реализует интерфейс fmt.Stringer. Разве ты не видишь 32.5253837/34.9408283?

Давайте сделаем одно изменение символа в программе и попробуем еще раз:

fmt.Println(&c)

Теперь вы увидите распечатанное 32.525384/34.940828.

Когда мы передаем значение из Coordinate в fmt.Println, Go печатает формат структуры по умолчанию. Когда мы передаем указатель от Coordinate до fmt.Println, он использует нашу пользовательскую печать.

Go spec — хорошее место для начала. В нем говорится:

— Набор методов определенного типа T состоит из всех методов, объявленных с типом приемника T.
— Набор методов указателя на определенный тип T (где T не является ни указателем, ни интерфейсом) — это набор все методы, объявленные с приемником *T или T.

Наш код подходит для первого случая, Coordinate.Stringer определено в приемнике указателя, но мы передаем значение Coordinate в fmt.Println. Что касается Go, мы не передавали параметр, реализующий fmt.Stringer, в fmt.Println, поэтому fmt.Println печатает форматирование структуры по умолчанию.

Если вам интересно, почему Go ведет себя так, вы можете прочитать Часто задаваемые вопросы. Или, что еще лучше, может наблюдая за Биллом Кеннеди объяснить, почему такое поведение является признаком того, что Го любит вас.



Если вам нравится решать задачи по программированию, ознакомьтесь с книгами Мики Тебека «Дразнилки для ума» на The Pragmatic Bookshelf. Вы можете сэкономить 35% на электронных версиях книг с промокодом brain_teasers_35 до 30 августа 2022 года: