DEV Community

Kllimenty Karavaev
Kllimenty Karavaev

Posted on

Тильда (~) в Go: что это и зачем нужно

Привет! Поговорим про оператор ~ в Go, который многих сбивает с толку. Спойлер: это не одна, а целых две разные фичи в зависимости от контекста!

🤔 "Это что за знак такой?"

Видите тильду в Go коде? Не паникуйте! Это либо:

  1. Битовый переворот (чаще всего)
  2. Магия дженериков (в Go 1.18+)

🔄 Битовый NOT: переворачиваем биты

Представьте, что у вас есть число, а тильда просто переворачивает все его биты в двоичном представлении:

x := 5               // 00000101 в двоичной системе счисления
result := ^x         // 11111010 в двоичной системе счисления
fmt.Println(result)  // 250 для uint8, -6 для int8
Enter fullscreen mode Exit fullscreen mode

Простая аналогия: как если бы вы инвертировали цвета в фотошопе — белое становится черным, черное белым.

Где полезно:

  • Работа с битовыми масками
  • Шифрование и низкоуровневые операции
  • Оптимизация памяти
// Пример: проверка бита
const ReadPermission = 1 << 0 // 00000001
const WritePermission = 1 << 1 // 00000010

// Инвертируем маску чтобы получить все КРОМЕ определенных битов
allExceptWrite := ^WritePermission
Enter fullscreen mode Exit fullscreen mode

🎯 Тильда в дженериках: aka "примерно такой тип"

С Go 1.18 тильда получила особое значение в дженериках:

// Ждет именно int
func StrictDouble[T int](x T) T { return x * 2 }

// Принимает любой тип с underlying type int
func FlexibleDouble[T ~int](x T) T { return x * 2 }

type MyInt int

func main() {
    var num MyInt = 5
    FlexibleDouble(num) // ✅ Работает!
    StrictDouble(num)   // ❌ Ошибка компиляции
}
Enter fullscreen mode Exit fullscreen mode

Перевод на человеческий: ~int значит "любой тип, который под капотом является int". Не дискриминирует алиасы :)

💡 Практические советы

  1. Не путайте контексты:

    • В выражениях: ^x → битовая операция
    • В дженериках: [T ~int] → ограничение типа
  2. Для битовых операций:

   // Включение бита
   flags |= mask

   // Выключение бита
   flags &^= mask  // AND NOT

   // Инверсия битов
   flags = ^flags
Enter fullscreen mode Exit fullscreen mode
  1. В дженериках используйте ~ когда хотите принимать кастомные типы с нужным underlying type.

🚀 Итого

  • ~ — это два разных оператора в одном флаконе
  • Битовый NOT: переворачиваем биты
  • Approximation constraint: говорим дженерикам "принимай примерно такие типы"

Top comments (0)