По всем вопросам- @haarrp
@itchannels_telegram - 🔥полезные ит-каналы
https://t.me/Golang_google - Golang программирование
@golangl - golang chat
@GolangJobsit - golang channel jobs
@golang_jobsgo - go chat jobs
Post #773
2.82K
🐹 Задача с подвохом: Generics и интерфейсы (Go 1.24)
Условие:
Что выведет следующий код и почему?
❓ Вопрос:
Что будет напечатано? Почему результат может удивить даже опытных Go-разработчиков?
🔍 Разбор:
Этот код использует generics и проверяет, реализует ли
Пошагово:
1️⃣
Тип
```go
func (m MyInt) String() string { ... }
```
2️⃣
-
- В строке:
- Приведение типа успешно, потому что
- Печатается:
```
Stringer: MyInt: 5
```
3️⃣
- Тип
-
- Приведение
- Печатается:
```
Default: 10
```
✅ Ожидаемый вывод:
```
Stringer: MyInt: 5
Default: 10
```
💥 Подвох:
- Даже если
- Многие забывают, что встроенные типы (int, string, и т.д.) никогда не реализуют интерфейсы напрямую, даже если они похожи на пользовательские типы.
- Ключевой момент:
🆕 Почему это актуально для Go 1.24:
Generics в Go 1.22+ улучшились по типовой проверке и стали более гибкими. Go 1.24 сделал generics более стабильными и оптимизированными, но все еще важно понимать различия между типами и интерфейсами, особенно при работе с
🛡️ Лайфхак:
Если вы хотите печатать всё одинаково для типов с
```go
func printValue2[T fmt.Stringer](val T) {
fmt.Println("Stringer (generic):", val.String())
}
```
✅ Вывод:
Generics упрощают код, но внимательность к типам и их интерфейсам критически важна. Даже небольшие различия между
Условие:
Что выведет следующий код и почему?
package main
import (
"fmt"
)
type Stringer interface {
String() string
}
type MyInt int
func (m MyInt) String() string {
return fmt.Sprintf("MyInt: %d", m)
}
func printValue[T any](val T) {
var s Stringer
if v, ok := any(val).(Stringer); ok {
s = v
}
if s != nil {
fmt.Println("Stringer:", s.String())
} else {
fmt.Println("Default:", val)
}
}
func main() {
var x MyInt = 5
printValue(x)
printValue(10)
}
❓ Вопрос:
Что будет напечатано? Почему результат может удивить даже опытных Go-разработчиков?
🔍 Разбор:
Этот код использует generics и проверяет, реализует ли
val интерфейс Stringer.Пошагово:
1️⃣
var x MyInt = 5 Тип
MyInt реализует интерфейс Stringer через метод:```go
func (m MyInt) String() string { ... }
```
2️⃣
printValue(x) -
val здесь типа MyInt. - В строке:
any(val).(Stringer) - Приведение типа успешно, потому что
MyInt реализует Stringer. - Печатается:
```
Stringer: MyInt: 5
```
3️⃣
printValue(10) - Тип
val здесь int. -
int не реализует Stringer. - Приведение
any(val).(Stringer) не срабатывает (ok == false). - Печатается:
```
Default: 10
```
✅ Ожидаемый вывод:
```
Stringer: MyInt: 5
Default: 10
```
💥 Подвох:
- Даже если
MyInt — это просто int, метод String() делает его другим типом, который реализует интерфейс. - Многие забывают, что встроенные типы (int, string, и т.д.) никогда не реализуют интерфейсы напрямую, даже если они похожи на пользовательские типы.
- Ключевой момент:
any(val) оборачивает значение в интерфейс{}, поэтому приведение типа срабатывает только если исходный тип действительно реализует интерфейс.🆕 Почему это актуально для Go 1.24:
Generics в Go 1.22+ улучшились по типовой проверке и стали более гибкими. Go 1.24 сделал generics более стабильными и оптимизированными, но все еще важно понимать различия между типами и интерфейсами, особенно при работе с
any и приведения типов внутри параметризованных функций.🛡️ Лайфхак:
Если вы хотите печатать всё одинаково для типов с
String(), можно сделать generic-констрейн с интерфейсом:```go
func printValue2[T fmt.Stringer](val T) {
fmt.Println("Stringer (generic):", val.String())
}
```
✅ Вывод:
Generics упрощают код, но внимательность к типам и их интерфейсам критически важна. Даже небольшие различия между
int и MyInt влияют на поведение программы.- 👎 7
- ❤ 3
- 👍 3
- 🔥 1


