Menu
Coddy logo textTech

Пустой интерфейс (any)

Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy — урок 28 из 107.

Пустой интерфейс — это интерфейс с нулевым количеством методов. Поскольку каждый тип в Go имеет как минимум ноль методов, любой тип автоматически удовлетворяет пустому интерфейсу. Это позволяет ему хранить значения любого типа.

var anything interface{}

anything = 42
anything = "hello"
anything = true
anything = []int{1, 2, 3}

Начиная с Go 1.18, ключевое слово any было введено как псевдоним для interface{}. Они полностью взаимозаменяемы, но any читается легче.

var value any = "Go is awesome"

Пустой интерфейс полезен, когда вам нужно работать со значениями неизвестных или различных типов. Функции, такие как fmt.Println, используют его для приема аргументов любого типа:

func PrintAnything(v any) {
    fmt.Println("Value:", v)
}

func main() {
    PrintAnything(100)
    PrintAnything("text")
    PrintAnything(3.14)
}

Однако здесь есть компромисс. Когда значение сохраняется в пустом интерфейсе, вы теряете доступ к информации о его конкретном типе.

Вы не можете напрямую вызывать методы или обращаться к полям, не извлекая предварительно базовый тип. В следующих уроках будет рассмотрено, как извлечь конкретный тип из пустого интерфейса с помощью утверждений типа (type assertions) и переключателей типов (type switches).

challenge icon

Задание

Легко

Давайте создадим гибкий контейнер для хранения, который может содержать значения любого типа, используя пустой интерфейс. Вы создадите простую коробку, которая демонстрирует, как any позволяет хранить разные типы в одной и той же структуре.

Вы организуете свой код в двух файлах:

  • box.go: Определите структуру Box с единственным полем Content типа any. Создайте функцию-конструктор NewBox, которая принимает значение любого типа и возвращает указатель на Box, содержащий это значение. Добавьте метод Describe, который возвращает строку, показывающую, что хранится в коробке.
  • main.go: Считайте различные значения из входных данных, создайте коробки, содержащие целое число, строку и логическое значение, затем выведите описание каждой коробки, чтобы показать, как один и тот же тип Box может содержать совершенно разные значения.

Будут предоставлены следующие входные данные:

  • Строка 1: Целочисленное значение
  • Строка 2: Строковое значение
  • Строка 3: Логическое значение (true или false)

Ваш метод Describe должен возвращать строку в следующем формате:

Box contains: [value]

Например, для входных данных 42, hello и true ваш вывод должен быть следующим:

Box contains: 42
Box contains: hello
Box contains: true

Ключевая идея здесь заключается в том, что ваша единственная структура Box может хранить целое число, строку или логическое значение — и все это благодаря тому, что тип any принимает значения любого типа. Каждая коробка содержит что-то свое, но при этом все они относятся к одному и тому же типу Box.

Шпаргалка

Пустой интерфейс (interface{}) — это интерфейс с нулем методов. Поскольку каждый тип в Go имеет как минимум ноль методов, каждый тип автоматически удовлетворяет пустому интерфейсу, что позволяет ему хранить значения любого типа.

var anything interface{}

anything = 42
anything = "hello"
anything = true
anything = []int{1, 2, 3}

Начиная с Go 1.18, ключевое слово any было введено как псевдоним для interface{}. Они полностью взаимозаменяемы, но any легче читать:

var value any = "Go is awesome"

Пустой интерфейс полезен для работы со значениями неизвестных или различных типов. Функции могут принимать аргументы любого типа:

func PrintAnything(v any) {
    fmt.Println("Value:", v)
}

func main() {
    PrintAnything(100)
    PrintAnything("text")
    PrintAnything(3.14)
}

Компромисс: Когда значение хранится в пустом интерфейсе, вы теряете доступ к информации о его конкретном типе. Вы не можете напрямую вызывать методы или обращаться к полям, не извлекая сначала базовый тип с помощью утверждений типа (type assertions) или переключателей типов (type switches).

Попробуйте сами

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Чтение целочисленного значения
	line1, _ := reader.ReadString('\n')
	intVal, _ := strconv.Atoi(strings.TrimSpace(line1))

	// Чтение строкового значения
	line2, _ := reader.ReadString('\n')
	strVal := strings.TrimSpace(line2)

	// Чтение логического значения
	line3, _ := reader.ReadString('\n')
	boolVal, _ := strconv.ParseBool(strings.TrimSpace(line3))

	// TODO: Создайте контейнеры для каждого значения с помощью NewBox
	// TODO: Выведите описание каждого контейнера с помощью метода Describe

	// Используйте переменные, чтобы избежать ошибок компиляции (удалите эти строки при реализации)
	_ = intVal
	_ = strVal
	_ = boolVal

	// Пример формата вывода:
	// fmt.Println(box.Describe())
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование