Как объявить переменную в visual studio
Объявить можно переменную любого действительного типа. Важно подчеркнуть, что возможности переменной определяются ее типом. Например, переменную типа bool нельзя использовать для хранения числовых значений с плавающей точкой. Кроме того, тип переменной нельзя изменять в течение срока ее существования. В частности, переменную типа int нельзя преобразовать в переменную типа char.
Инициализация переменной
Задать значение переменной можно, в частности, с помощью оператора присваивания. Кроме того, задать начальное значение переменной можно при ее объявлении. Для этого после имени переменной указывается знак равенства (=) и присваиваемое значение. Если две или более переменные одного и того же типа объявляются списком, разделяемым запятыми, то этим переменным можно задать, например, начальное значение. Ниже приведена общая форма инициализации переменной:
Переменные, являющиеся полями класса или структуры, если не инициализированы явно, по умолчанию обнуляются в момент создания.
Переменные, локальные по отношению к методу, должны быть явно инициализированы в коде до появления любого оператора, в котором используются их значения. В данном случае при объявлении переменной ее инициализация не происходит автоматически, но компилятор проверит все возможные пути потока управления в методе и сообщит об ошибке, если обнаружит любую возможность использования значения этой локальной переменной до ее инициализации.
Динамическая инициализация
В данном примере объявляются три локальные переменные i1, i2, result, первые две из которых инициализируются константами, а переменная result инициализируется динамически с использованием метода Math.Sqrt(), возвращающего квадратный корень выражения. Следует особо подчеркнуть, что в выражении для инициализации можно использовать любой элемент, действительный на момент самой инициализации переменной, в том числе вызовы методов, другие переменные или литералы.
Неявно типизированные переменные
Неявно типизированная переменная объявляется с помощью ключевого слова var и должна быть непременно инициализирована. Для определения типа этой переменной компилятору служит тип ее инициализатора, т.е. значения, которым она инициализируется:
Единственное отличие неявно типизированной переменной от обычной, явно типизированной переменной, — в способе определения ее типа. Как только этот тип будет определен, он закрепляется за переменной до конца ее существования.
Давайте рассмотрим пример, где в консоль будем выводить типы неявно типизированных переменных:
В остальной части данного раздела описывается форма и значение объявлений для переменных типов, включенных в этот список. В частности, в остальных разделах объясняется, как объявить следующие объекты.
Тип переменной | Описание |
---|---|
Простые переменные | Однозначные переменные целочисленного типа или типа с плавающей запятой |
Массивы | Переменные, состоящие из коллекции элементов того же типа |
Указатели | Переменные, указывающие на другие переменные и содержащие расположения переменных (в виде адресов) вместо значений |
Переменные перечисления | Простые переменные с целочисленным типом, содержащие одно значение из набора именованных целочисленных констант |
Структуры | Переменные, состоящие из коллекции значений, которые могут иметь разные типы |
Объединения | Переменные, состоящие из нескольких значений разных типов, занимающих одинаковое пространство для хранения |
Оператор объявления — это часть объявления, задающая имя, которое нужно вставить в программу. Он может включать модификаторы, например * (указатель на), и любые ключевые слова соглашения о вызовах Майкрософт.
Блок, относящийся только к системам Microsoft
В этом операторе объявления
char — это описатель типа, __declspec(thread) и * — это модификаторы, а var — это имя идентификатора.
Завершение блока, относящегося только к системам Майкрософт
Деклараторы используются для объявления массивов значений, указателей на значения и функций, возвращающих значения заданного типа. Деклараторы отображаются в объявлениях массивов и указателей, описанных далее в этом разделе.
Синтаксис
direct-declarator :
identifier
( declarator )
direct-declarator [ constant-expression opt ]
direct-declarator ( parameter-type-list )
direct-declarator ( identifier-list opt )
pointer :
* type-qualifier-list необ.
* type-qualifier-list необ. pointer
type-qualifier-list :
type-qualifier
type-qualifier-list type-qualifier
См. соответствующий синтаксис для declaration в статьях Общие сведения об объявлениях или Краткие сведения о синтаксисе языка C для получения сведений о синтаксисе, который ссылается на declarator .
Если декларатор состоит из неизмененного идентификатора, объявляемый элемент имеет базовый тип. Если звездочка ( * ) отображается слева от идентификатора, тип изменяется на тип указателя. Если после идентификатора следуют квадратные скобки ( [ ] ), тип изменяется на тип массива. Если после идентификатора указываются скобки, тип меняется на тип функции. Дополнительные сведения об интерпретации приоритетности в пределах объявлений см. в статье Интерпретация сложных операторов объявлений.
Каждый декларатор объявляет по крайней мере один идентификатор. Декларатор должен включать описатель типа, чтобы называться полным объявлением. Описатель типа предоставляет тип элементов типа массива, тип объекта, к которому относится тип указателя, или тип возвращаемого значения функции.
Объявления массивов и указателей более подробно обсуждаются далее в этом разделе. В следующем примере проиллюстрировано несколько простых форм деклараторов.
Блок, относящийся только к системам Microsoft
Компилятор Microsoft для C не ограничивает число операторов объявления, которые могут изменять арифметические, структурные типы или типы объединений. Это число ограничивается только объемом доступной памяти.
Завершение блока, относящегося только к системам Майкрософт
Out переменные
Сейчас использовать out переменные не так легко, как нам хотелось бы. Перед тем как вызвать метод с out аргументами, необходимо объявить переменные, которые будут переданы в этот метод. Так как обычно значения этим переменным во время объявления не присваиваются (что логично — они все равно будут перезаписаны методом), ключевое слово var использовать не получится. Надо объявлять переменные с указанием их типа:
Область видимости для таких переменных является внешний блок, именно поэтому можно их использовать в следующем за вызовом метода выражении.
Внимание: В Preview 4 действуют более строгие ограничения на область видимости: out переменные можно использовать только внутри выражения, где они были определены. Поэтому для того, чтобы вышеуказанный пример заработал, надо дождаться следующего релиза.
Так как объявление out переменных происходит в том же выражении, что и их передача в качестве аргументов метода, компилятор может вывести их тип (если для этого метода нет конфликтующих перегрузок), поэтому вместо типа можно использовать ключевое слово var:
Out аргументы широко используются в семействе методов Try. , где возвращаемое булево значение показывает успех операции и out аргументы содержат полученное значение:
Внимание: В данном примере i используется только внутри блока if, в котором определена, поэтому в Preview 4 этот пример тоже работает.
Сопоставление с шаблоном
- is теперь может использоваться не только с типом, но и с шаблоном (в качестве правого аргумента).
- case в операторе switch теперь может использовать шаблоны, а не только константы.
Шаблоны с is
Рассмотрим простой пример, в котором используются и константный шаблон, и шаблон типа.
Как видно из примера, переменные шаблона (которые были объявлены в шаблоне), имеют ту же область видимости, что и out переменные, поэтому могут использоваться внутри внешнего блока видимости.
Внимание: В Preview 4 для переменных шаблона так же, как и для out переменных, действуют более строгие правила видимости, поэтому пример заработает только в следующих релизах.
Шаблоны и Try-методы могут использоваться вместе:
Шаблоны и выражение switch
Варианты использования switch были расширены, теперь можно:
- Использовать любые типы (не только примитивные).
- Использовать шаблоны в выражениях case.
- Добавлять дополнительные условия к выражениям case (используя ключевое слово when).
Отметим следующие особенности нового расширенного switch:
Кортежи
Иногда хочется вернуть несколько значений из метода. Ни один из доступных на сегодняшний момент способов не выглядит оптимальным:
-
Out параметры: синтаксис выглядит перегруженным (даже если использовать рассмотренные выше нововведения), неприменимо к асинхронным методам.
Теперь метод возвращает 3 строки, объединенных в кортеж. Вызывающий код может их использовать следующим образом:
Имена полей Item1, Item2, . являются именами по умолчанию для каждого кортежа, однако, есть возможность дать данным, объединенным в кортеж, имена получше:
Теперь к элементам кортежа можно обратиться так:
Также имена элементов можно указать сразу в литерале кортежа:
Кортежи можно присваивать друг другу, если имена их элементов не совпадают: главное, чтобы сами элементы можно было присваивать друг другу. В будущем будут добавлены ограничения, в основном для литералов кортежей, которые будут сигнализировать о таких ошибках, как случайно поменянные местами имена элементов и т.д. В Preview 4 таких ограничений еще нет.
Кортежи представляют собой значимый тип, а их элементы — изменяемые открытые поля. Кортежи могут сравниваться на равенство: два кортежа равны (и имеют одинаковый хэш код), если все составляющие элементы равны друг с другом попарно (и имеют одинаковый хэш код). Такое поведение делает кортежи полезными не только для возвращения нескольких значений из метода. Например, если вам нужен словарь с составным ключом, используйте в качестве ключа кортеж. Если вам нужен список, где на каждой позиции должно быть несколько значений, также использует список кортежей. (От переводчика: не надо воспринимать это как руководство к использованию кортежей в 100% ситуациях, иногда простой класс с парой-тройкой свойств лучше выразит ваши намерения и будет легче поддерживаем в будущем).
Распаковка кортежей
Еще один способ работы с кортежем — его распаковка, которая заключается в присваивании его элементов новым переменным:
Также можно использовать ключевое слово var вместо типа для каждой переменной:
Или даже поместить var перед скобками:
Также распаковать кортеж можно в уже объявленные переменные:
Распаковать можно не только кортеж, любой тип может быть распакован. Для этого он должен иметь метод следующего вида:
Out параметры соответствуют значениям, которые будут присвоены в результате распаковки. Почему используются out параметры, а не кортежи? Чтобы можно было иметь несколько перегрузок метода с разным количеством параметров.
Такой подход позволит создавать «симметричные» конструктор и метод распаковки.
Так же как и для out переменных мы планируем добавить подстановочные символы для игнорирования некоторых возвращаемых параметров.
Локальные функции
Иногда вспомогательная функция имеет смысл только внутри одного метода, в котором вызывается. Теперь такую функцию можно объявить внутри метода:
Аргументы внешнего метода и его локальные переменные доступны для локальной функции, так же как и для лямбда-выражений.
В качестве еще одного примера рассмотрим метод, реализованный как итератор. В этом случае такому методу обычно требуется неитерирующий метод-обертка для проверки аргументов (потому что сам итератор не вызывается, пока не будет вызван метод MoveNext).
С помощью локальных функций такая задача решается изящнее, чем обычно:
Если бы метод Iterator был обычным приватным методом, то он мог быть вызван случайно, без проверки аргументов. Кроме того, ему потребовалось бы передавать те же самые аргументы, что и методу Filter.
Внимание: В Preview 4 локальные функции должны быть объявлены перед вызовом. В будущем это ограничение будет ослаблено: локальные функции можно будет вызвать после того, как всем локальным переменные, ими используемые, будут присвоены значения.
Улучшения литералов
Локальные переменные и возвращаемые значения по ссылке
Теперь можно не только передать параметры в метод по ссылке (с помощью ключевого слова ref), но и возвратить данные из метода по ссылке, а также сохранить в локальной переменной тоже по ссылке.
Теперь будет удобно передавать ссылки на определенные места в больших структурах данных. Например, в игре информация содержится в большом заранее выделенном массиве структур (чтобы избежать пауз на сбор мусора). Теперь методы могут вернуть ссылку на одну из таких структур, с помощью которой вызывающий код может читать и изменять эту структуру.
Для того, чтобы работать с ссылками было безопасно, введены следующие ограничения:
- Можно возвращать только ссылки, которые возвращать безопасно: ссылки на объекты, переданные в метод и ссылки на поля объектов.
- Переменные инициализируются определенной ссылкой и в будущем не меняются.
Расширение списка типов, возвращаемых асинхронными методами
Конечно, можно придумать и другие ситуации, в которых Task-подобные объекты будут полезны. Правильное создание таких типов не будет простой задачей, поэтому мы не ожидаем, что большое число разработчиков будут создавать их, однако мы думаем, что в различных фреймворках они будут полезны, и вызывающий код сможет просто использовать await, как сейчас для Task.
Внимание: В Preview 4 эти типы еще не доступны.
Больше членов класса в виде выражений
Это пример новой функциональности, добавленной сообществом, а не командой разработки компилятора! Ура, опен сорс!
Внимание: В Preview 4 поддержка этих членов класса недоступна.
Throw выражения
Внимание: В Preview 4 такие выражения еще не доступны.
Заключение
В своей работе с замечательным дополнением ReSharper в Visual Studio я постоянно сталкивался с предложением вместо явного объявления типа переменных использовать объявления типа в неявной форме с использованием var. Сначала меня это несколько удивило, но я особо не обратил внимание. Но по прошествии некотрого времени такие предложения стали уже напрягать и я решил разобраться в чем же суть такой оптимизации.
- использование var потребуется вам для определения переменной с анонимным типом. Тут все просто — вы не сможете определить переменную анонимного типа без использования var;
- использование var принуждает вас более грамотно называть сами переменные. Когда вы читаете определение переменной с явным типом, то получаете больше информации и что-нибудь типа «IUnitTestElement current» имеет смысл. Тем не менее, когда локальная переменная используется дальше, вы прочитаете «current», что потребует от вас больше времени понять что она означает. Использование «var currentElement» позволяет более быстро понимать переменную в любом месте кода;
- использование var принуждает к более качественному API. Во-первых, вы получите оптимальные типы, когда позволяете компилятору получать самому тип возвращаемого значения метода или свойства. И еще вы вынуждены будете более правильно называть свои методы, чтобы они явно указывали на то, что возвращают;
- использование var принуждает к инициализации переменных при их объявлении. В общем случае, инициализация переменных при определении является хорошим тоном, а в нашем случае, компилятор обязательно требует такую инициализация при определении переменной через var;
- использование var приводит к уменьшению «шума» в коде. Существует множество случаев, когда объявленные неявно переменные уменьшают количество текста, который приходится читать разработчику и который он мог бы пропустить. Если мы не используем var, то определение переменной через выражение new или cast требует указание типа дважды. Когда мы имеем дела с обобщениями (generics), то такое положение дел приведет к появлению большого количества излишнего, чрезмерного кода (redundant code). Еще одним подобным примером может стать переменная итерации в foreach для типа наподобие «Dictionary»;
- использование var позволяет уменьшить использование директивы using. С var у вас нет явных ссылок на типы, и так как компилятор определит тип за вас, то вам не нужно импортировать пространства имен, когда вам требуется какая-нибудь временная переменная.
Как думает общественность, обоснованы ли доводы Ильи и, значит, ReSharper на повсеместное использование var вместо явного указания типа? Лично для меня доводы приведенные в статье показались весомыми и даже правильными. Кто как думает?
Область видимости, или контекст переменной — это часть кода, в пределах которого доступна данная переменная. В общем случае такая область определяется описанными ниже правилами:
Поле, также известное как переменная-член класса, находится в области видимости до тех пор, пока в этой области находится содержащий поле класс.
Локальная переменная находится в области видимости до тех пор, пока закрывающая фигурная скобка не укажет конец блока операторов или метода, в котором она объявлена.
Локальная переменная, объявленная в операторах цикла for, while или подобных им, видима в пределах тела цикла.
Конфликты областей видимости локальных переменных
Использование в больших программах одних и тех же имен переменных в разных частях программы является обычной практикой. Это нормально до тех пор, пока области видимости этих переменных не перекрываются и находятся в совершенно разных частях программы, таким образом исключая любую неоднозначность. Однако следует иметь в виду, что локальные переменные с одним и тем же именем не могут быть объявлены дважды в одном и том же контексте, поэтому вы не сможете поступить так, как показано ниже:
Рассмотрим следующий пример кода:
Важно отметить, что переменная i объявляется в этом коде два раза в пределах одного и того же метода. Это можно делать, поскольку переменные i объявляются в двух отдельных циклах, поэтому каждая из них локальна в пределах собственного цикла.
Вот другой пример:
ScopeTest.cs (12,15) : error CS0136: A local variable named '3' cannot be declared in this scope because it would give a different meaning to 'j', which is already used in a 'parent or current' scope to denote something else
Дело в том, что переменная j, которая определена перед началом цикла for, внутри цикла все еще находится в области видимости и не может из нее выйти до завершения метода Main(). Хотя вторая переменная j (недопустимая) объявлена в контексте цикла, этот контекст вложен в контекст метода Main(). Компилятор не может различить эти две переменных, поэтому не допустит объявления второй из них.
Конфликты областей видимости полей и локальных переменных
Этот код компилируется, несмотря на то, что здесь в контексте метода Main() присутствуют две переменных с именем j: переменная j, определенная на уровне класса и существующая до тех пор, пока не будет уничтожен класс (когда завершится метод Main(), а вместе с ним и программа), и переменная j, определенная внутри Main(). В данном случае новая переменная с именем j, объявленная в методе Main(), скрывает переменную уровня класса с тем же именем. Поэтому когда вы запустите этот код, на дисплее будет отображено число 30.
Константы
Как следует из названия, константа — это переменная, значение которой не меняется за время ее существования. Предваряя переменную ключевым словом const при ее объявлении и инициализации, вы объявляете ее как константу:
Ниже перечислены основные характеристики констант:
Они должны инициализироваться при объявлении, и однажды присвоенные им значения никогда не могут быть изменены.
Значение константы должно быть вычислено во время компиляции. Таким образом, инициализировать константу значением, взятым из другой переменной, нельзя. Если все-таки нужно это сделать, используйте поля только для чтения.
Константы всегда неявно статические. Однако вы не должны (и фактически не можете) включать модификатор static в объявление константы.
Использование констант в программах обеспечивает, по крайней мере, три преимущества:
Константы облегчают чтение программ, заменяя "магические" числа и строки читаемыми именами, назначение которых легко понять.
Читайте также: