:github_url: hide .. _class_Variant: Variant ======= Самый важный тип данных в Godot. .. rst-class:: classref-introduction-group Описание ---------------- В компьютерном программировании класс Variant — это класс, который предназначен для хранения множества других типов. Динамические языки программирования, такие как PHP, Lua, JavaScript и GDScript, любят использовать их для хранения данных переменных на бэкэнде. С этими Variant свойства могут свободно менять типы значений. .. tabs:: .. code-tab:: gdscript var foo = 2 # foo — это динамическое целое число foo = "Теперь foo — это строка!" foo = RefCounted.new() # foo — это объект var bar: int = 2 # bar — статически типизированное целое число. # bar = "Ой-ой! Я не могу сделать так, чтобы статически типизированные переменные стали другим типом!" .. code-tab:: csharp // C# статически типизирован. Как только переменная получает тип, ее нельзя изменить. Вы можете использовать ключевое слово `var`, чтобы компилятор автоматически вывел тип. var foo = 2; // Foo — это 32-битное целое число (int). Будьте осторожны, целые числа в GDScript — 64-битные, а их прямой эквивалент в C# — `long`. // foo = "foo было и всегда будет целым числом. Его нельзя преобразовать в строку!"; var boo = "Boo — это строка!"; var ref = new RefCounted(); // var особенно полезен при использовании вместе с конструктором. // Godot также предоставляет тип Variant, который работает как объединение всех совместимых с Variant типов. Variant fooVar = 2; // fooVar — это динамическое целое число (хранящееся как `long` в типе Variant). fooVar = "Теперь fooVar — это строка!"; fooVar = new RefCounted(); // fooVar — это GodotObject. Godot отслеживает все переменные API скриптов в Variants. Даже не осознавая этого, вы постоянно используете Variants. Когда определенный язык применяет собственные правила для сохранения типизированных данных, то этот язык применяет собственную логику к базовому API скриптов Variant. - GDScript автоматически оборачивает в них значения. Он хранит все данные в простых Variant по умолчанию, а затем опционально применяет пользовательские правила статической типизации к типам переменных. - C# является статически типизированным, но использует собственную реализацию типа Variant вместо класса Godot **Variant**, когда ему нужно представить динамическое значение. Variant C# может быть назначен любой совместимый тип неявно, но преобразование требует явного приведения. Глобальная функция :ref:`@GlobalScope.typeof()` возвращает перечислимое значение типа Variant, сохраненного в текущей переменной (см. :ref:`Variant.Type`). .. tabs:: .. code-tab:: gdscript var foo = 2 match typeof(foo): TYPE_NIL: print("foo это null") TYPE_INT: print("foo — целое число") TYPE_OBJECT: # Обратите внимание, что объекты — это отдельная особая категория. # Чтобы получить имя базового типа объекта, вам понадобится метод `get_class()`. print("foo is a(n) %s" % foo.get_class()) # вставьте имя класса в отформатированную строку. # Обратите внимание, что при этом не получается глобальный идентификатор `class_name` скрипта. # Если требуется `class_name`, используйте вместо этого `foo.get_script().get_global_name()`. .. code-tab:: csharp Variant foo = 2; switch (foo.VariantType) { case Variant.Type.Nil: GD.Print("foo это null"); break; case Variant.Type.Int: GD.Print("foo — целое число"); break; case Variant.Type.Object: // Обратите внимание, что объекты — это отдельная особая категория. // Вы можете преобразовать Variant в GodotObject и использовать рефлексию, чтобы получить его имя. GD.Print($"foo is a(n) {foo.AsGodotObject().GetType().Name}"); break; } Variant занимает всего 20 байт и может хранить внутри себя практически любой тип данных движка. Variant редко используются для хранения информации в течение длительного времени. Вместо этого они используются в основном для связи, редактирования, сериализации и перемещения данных. Godot специально инвестировал в то, чтобы сделать свой класс Variant максимально гибким; настолько, что он используется для множества операций, чтобы облегчить связь между всеми системами Godot. Variant: - Может хранить практически любой тип данных. - Может выполнять операции между многими вариантами. GDScript использует Variant в качестве своего атомарного/собственного типа данных. - Может быть хеширован, поэтому его можно быстро сравнивать с другими вариантами. - Может использоваться для безопасного преобразования между типами данных. - Может использоваться для абстрагирования вызывающих методов и их аргументов. Godot экспортирует все свои функции через Variant'ы. - Может использоваться для отсрочки вызовов или перемещения данных между потоками. - Может быть сериализован как двоичный и сохранен на диске или передан по сети. - Может быть сериализован в текст и использован для печати значений и редактируемых настроек. - Может работать как экспортируемое свойство, поэтому редактор может редактировать его универсально. - Может использоваться для словарей, массивов, парсеров и т. д. \ **Контейнеры (Array и Dictionary):** Оба реализованы с использованием вариантов. :ref:`Dictionary` может сопоставлять любой тип данных, используемый в качестве ключа к любому другому типу данных. :ref:`Array` просто содержит массив вариантов. Конечно, вариант также может содержать :ref:`Dictionary` и :ref:`Array` внутри, что делает его еще более гибким. Изменения контейнера изменят все ссылки на него. :ref:`Mutex` следует создать для его блокировки, если требуется многопоточный доступ. .. note:: Существуют заметные различия при использовании данного API с C#. Подробнее см. :ref:`doc_c_sharp_differences`. .. rst-class:: classref-introduction-group Обучающие материалы -------------------------------------- - :doc:`Введение вариативных классов <../engine_details/architecture/variant_class>` .. |virtual| replace:: :abbr:`virtual (Этот метод обычно должен быть переопределен пользователем, чтобы иметь какой-либо эффект.)` .. |required| replace:: :abbr:`required (This method is required to be overridden when extending its base class.)` .. |const| replace:: :abbr:`const (Этот метод не имеет побочных эффектов. Он не изменяет ни одну из переменных-членов экземпляра.)` .. |vararg| replace:: :abbr:`vararg (Этот метод принимает любое количество аргументов после описанных здесь.)` .. |constructor| replace:: :abbr:`constructor (Этот метод используется для создания типа.)` .. |static| replace:: :abbr:`static (Этот метод не нуждается в вызове экземпляра, поэтому его можно вызвать напрямую, используя имя класса.)` .. |operator| replace:: :abbr:`operator (Этот метод описывает допустимый оператор для использования с этим типом в качестве левого операнда.)` .. |bitfield| replace:: :abbr:`BitField (Это значение является целым числом, составленным как битовая маска следующих флагов.)` .. |void| replace:: :abbr:`void (Нет возвращаемого значения.)`