cpp

Сохранение в переменной данных произвольного типа

Если в качестве типа данных указать пустой интерфейс (interface{}), то в переменной можно будет сохранить данные произвольного типа:

var x interface{}
x = 10
fmt.Println(x)                  // 10
fmt.Printf("%T\n", x)           // int
x = 15.4
fmt.Println(x)                  // 15.4
fmt.Printf("%T\n", x)           // float64

Сохранить данные в переменной это лишь половина дела. Чтобы с этими данными выполнять какие-либо действия, нужно выполнить преобразование типов. Это в свою очередь требует умения определить тип данных, хранимых в переменной в данный момент времени. Если типы данных не совпадают, то будет ошибка на этапе выполнения и программа прекратит выполнение досрочно. Преобразование типов выполняется по следующей схеме:

var <Переменная 2> <Тип> = <Переменная 1>.(<Тип>)

Пример:

var x interface{} = 15
// var n int = x       // Ошибка !
// cannot use x (type interface {}) as type int in assignment:
// need type assertion
var y int = x.(int)    // OK
fmt.Println(y)         // 15

Если тип не совпадает, то будет ошибка на этапе выполнения:

var z float64 = x.(float64) // Ошибка
// panic: interface conversion: interface {} is int, not float64

Чтобы избежать ошибки нужно воспользоваться следующим форматом:

<Переменная 2>, <OK> := <Переменная 1>.(<Тип>)

Если преобразование выполнено успешно, то параметр <OK> будет иметь значение true. В противном случае значение false. Ошибка при неудачном преобразовании не выводится:

var x interface{} = 15
y, ok1 := x.(int)
fmt.Println(y)         // 15
fmt.Println(ok1)       // true
z, ok2 := x.(float64)
fmt.Println(z)         // 0
fmt.Println(ok2)       // false

Определить тип переменной и сразу выполнить преобразование типа позволяет оператор switch. Оператор имеет следующий формат:

switch [<Переменная 2> := ]<Переменная 1>.(type) {
case <Тип 1>:
   <Блок, выполняемый, если тип соответствует типу <Тип 1>>
case <Тип N>:
   <Блок, выполняемый, если тип соответствует типу <Тип N>>
default:
   <Если другой тип>
}

В зависимости от типа переменной <Переменная 1> будет выполнен один из блоков case, тип которого совпадает. Через переменную <Переменная 2> внутри блоков case доступно значение после преобразования типа. Если не один из блоков case не совпадает с типом, то выполняется блок default. Внутри блока default переменная <Переменная 2> будет иметь тип interface{}. Пример:

var x interface{} = 15.4
switch v := x.(type) {
case int:
   fmt.Println("int:", v)
   var y int = v
   fmt.Println("y =", y)
case float64:
   fmt.Println("float64:", v)
   var y float64 = v
   fmt.Println("y =", y)
default:
   fmt.Println("Другой тип")
}

Результат:

float64: 15.4
y = 15.4

Если первую строку изменить следующим образом:

var x interface{} = 15

то результат будет таким:

int: 15
y = 15

Вместо оператора switch можно использовать оператор if:

var x interface{} = 15.4
if v, ok := x.(int); ok {
   fmt.Println("int:", v)
   var y int = v
   fmt.Println("y =", y)
} else if v, ok := x.(float64); ok {
   fmt.Println("float64:", v)
   var y float64 = v
   fmt.Println("y =", y)
} else {
   fmt.Println("Другой тип")
}

Учебник Go (Golang)
Учебник Go (Golang) в формате PDF

Реквизиты

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов

cpp