#17.2 Пустой интерфейс - какой угодно тип (тип any)
Primary tabs
Forums:
Начиная с версии Go 1.18, появился тип any, он является синонимом на interface{} (пустой интерфейс).
Пример использования в стандартных функциях
Пустой интерфейс может содержать значение любого типа, что делает его универсальным контейнером для данных. Рассмотрим пример:
package main
import "fmt"
func main() {
fmt.Print(1, 1.21, "hi")
}
-- в этом простом пример функция fmt.Print() принимает любой тип данных (any) и проверяет, какое значение мы передали, чтобы его вывести.
При выполнении программы будет выведено что-то вроде:
1 1.21hi
Рассмотрим более сложный пример, где добавим к структуре метод:
type Wallet struct {
Cash int
}
// Навесим метод со стандартным именем
// ответчающим за строковое предлставление%:
func (w *Wallet) String() string {
return "Остаток на счете " +
strconv.Itoa(w.Cash) + " рублей"
}
func main() {
wall := &Wallet{
Cash: 10,
}
fmt.Print(wall)
}
При выполнении программы будет выведено:
Остаток на счете 10 рублей.
-- это так потому, что если переданный в тип реализует interface fmt.Stringer, то результат вывода будет определяться за счет выполнения метода String.
Преобразование any к конкретному типу
Расмотрим преобразование типа any к интерфейсу, сделаем этон а примере функции Buy3(), написанной по аналогии с примерами Buy() и Buy2() из урока по интерфейсам:
// Обший интерфес "Платильщик"
type Payer interface {
pay(int) error // что-то оплачиваем
getBalance() int // узнаем сколько денег еще осталось
}
type Wallet struct {
cash int
}
// навешиваем метод на структуру
func (w *Wallet) pay(amount int) error {
if w.cash < amount {
return fmt.Errorf("не хватает денег в кошельке")
}
w.cash -= amount
return nil
}
func (w *Wallet) getBalance() int {
return w.cash
}
// Структура описывающая банковскую карточку
type Card struct {
Balance int
ValidUntil string
Cardholder string
CVV string
Number string
}
func (c *Card) pay(amount int) error {
if c.Balance < amount {
return fmt.Errorf("не хватает денег на карте")
}
c.Balance -= amount
return nil
}
func (c *Card) getBalance() int {
return c.Balance
}
// Платежные аккаунт в какой-то системе
type KtuPay struct {
money int
ktuId string
}
func (a *KtuPay) pay(amount int) error {
if a.money < amount {
return fmt.Errorf("не хватает денег на аккаунте")
}
a.money -= amount
return nil
}
func (kp *KtuPay) getBalance() int {
return kp.money
}
// Покупка с проверкой типа платежного средства
func Buy3(in any, amount int) {
var (
p Payer
ok bool
)
// Проверяем соответсвует ли перменная in типу Payer
p, ok = in.(Payer)
if !ok {
fmt.Printf("\n %T не является платежным средством\n\n", in)
return
}
if err := p.pay(amount); err != nil {
fmt.Printf("Ошибка при оплате %T: %v\n\n", p, err)
return
}
fmt.Printf("Спасибо за покупку через %T\n", p)
}
// Произведем оплату разными средствами
func main() {
myWallet := &Wallet{cash: 100}
Buy3(myWallet, 10)
fmt.Println("Осталось монет:", myWallet.getBalance())
var myMoney Payer
myMoney = &Card{Balance: 80, Cardholder: "rvasily"}
Buy3(myMoney, 10)
fmt.Println("Осталось монет:", myMoney.getBalance())
myMoney = &KtuPay{money: 70}
Buy3(myMoney, 10)
fmt.Println("Осталось монет:", myMoney.getBalance())
// А вот строкой заплатить не получится:
Buy3("Привет!", 10)
}
-- в функцию Buy3() можно передавать вообще любой тип данных, если этот тип будет соотвествовать интерфейсу Payer, то будет произведена оплата, если запустить этот код, то получим распечатку:
Спасибо за покупку через *main.Wallet Осталось монет: 90 Спасибо за покупку через *main.Card Осталось монет: 70 Спасибо за покупку через *main.KtuPay Осталось монет: 60 string не является платежным средством
Проверка, скрывающегося под any - type switch
По аналогии ситуацией, когда мы уточняли какой именно тип скрывается под обычным (непустым) интерфейсом, с помощью type switch мы мы можем проверять соответствие другим более конкретным типам, если аргумент объявлен как any:"
Рассмотрим пример:
type Wallet struct {
cash int
}
func GoTypes(in any) {
switch typed := in.(type) {
case string:
fmt.Println("Обработали строку", typed)
case int:
fmt.Println("Обработали число", typed)
default:
fmt.Printf("Функция GoTypes не умеет обрабатывать: %T", in)
}
}
func main() {
GoTypes("hello")
GoTypes(1)
GoTypes(&Wallet{cash: 10})
}
-- после запуска получим распечатку:
Обработали строку hello Обработали число 1 Функция GoTypes не умеет обрабатывать: *main.Wallet
- Log in to post comments
- 64 reads