Что такое var в c
Перейти к содержимому

Что такое var в c

  • автор:

Что такое var в c

Ключевое слово var ссылается на тип неявным способом. Это псевдоним любого типа. Реальный тип определит компилятор C#. Использование var никак не ухудшает производительность. Var это отличный (и вкусный) синтаксический «сахар». Он делает программы короче и проще для чтения. Var может использоваться в коде методов и в теле циклов. Ключевое слово var может представлять любой тип, и какой это будет тип определяется во время компиляции. После компиляции результат получится тот же самый, как если бы тип был точно указан.

Рассмотрим примеры применения ключевого слова var. Ниже показано использование var в трех контекстах.

Примечание: для компиляции этой программы Вы не можете использовать старую версию .NET Framework (используйте .NET 2017).

using System;
using System.Collections.Generic;
using System.Linq;
class Program < public static void Main() < // 1. // var доступно всегда, не только в Linq. var cat = new List< int> < 1, 2, 7, 9 >; // Наведите курсор на ключевое слово 'var', и Visual Studio // скажет Вам какой реально тип здесь используется. 
// 2. // Этот пример отображает нечетные числа. // Возвращает IEnumerable < T>(где T это int). var items = from item in cat where (item % 2 == 1) select item;
// 3. // Каждый элемент имеет тип int. foreach (var item in items) < Console.WriteLine(item); >// Предыдущий цикл такой же, как и предыдущий: foreach (int item in items) < Console.WriteLine(item); >> >
1 7 9
1 7 9

Этот код использует ключевое слово var и тип List. Переменная известна как List. Таким образом, var относится к List элементов типа int.

Примечание: Вы можете навести курсор мыши на var, и среда Visual Studio подскажет, что это тип List. Эта функция называется IntelliSense.

В этом примере также показан запрос к элементам var, который возвращает IEnumerable< int>. Выражение запроса вычисляется для этого типа, и var неявно относится к этому типу.

Вы можете использовать var в цикле foreach — как Вы видите в этом примере, он работает точно так же, как или любая другая переменная.

Системы обработки типов. Язык C# использует строгий контроль типов. Области памяти помечены информацией о том, какие типы объектов в них содержатся. Строгий контроль типов помогает повысить качество кода. Компилятор C# будет выдавать ошибки и предупреждения, потому что хочет, чтобы Ваш код работал правильно. В случае var он анализирует код, и выводит из него тип переменной.

Ограничения. Вы не можете назначить var в значение null. Это приведет к предупреждению CS0825. Также Вы не можете использовать var в качестве типа параметра или возвращаемого значения метода.

Реализация. Давайте посмотрим на поведение реализации кода C#, который использует ключевое слово var. Реальное поведение кода C# отражает промежуточный язык (IL, Intermediate Language). Код IL можно посмотреть с помощью утилиты IL Disassembler, предоставляемой Visual Studio. В примере используются два значения типа int32, и эти два значения на IL абсолютно одинаковые, хотя одна декларация использует var, а другая int. Подсистема выполнения кода ничего не знает о том, что программист использовал var. Таким образом переменная, определенная с ключевым словом var, будет работать точно так же эффективно, как и переменная, определенная с явным указанием типа наподобие int или string.

public int ReturnValue() < var a = 5; int b = 5;
return a + b; >

Код IL этого метода:

.method public hidebysig instance int32 ReturnValue() cil managed < // Code size 9 (0x9) .maxstack 1 .locals init ([0] int32 result,
 [1] int32 CS$1$0000) IL_0000: nop IL_0001: ldc.i4.5 IL_0002: stloc.0 IL_0003: ldloc.0 IL_0004: stloc.1 IL_0005: br.s IL_0007 IL_0007: ldloc.1 IL_0008: ret > // end of method VarKW::ReturnValue 

Использование. Ключевое слово var полезно не только на обычных типах. Ниже показан тип Dictionary, использующий подробный синтаксис — много скобок, букв и запятых. Var позволяет опустить длинные списки типов параметров, что может улучшить читаемость кода. Var часто упрощает ревизию/переработку (refactoring) кода.

Примечание: когда при рефакторинге Вы меняете имя типа, то локальный тип var не нуждается в замене.

// Программа C#, использующая var для типа Dictionary.
using System;
using System.Collections.Generic;
class Program < static void Main() < // Использование ключевого слова var для создания экземпляра Dictionary. // Затем используем саму коллекцию. var data = new Dictionary< string, int>(); data.Add("cat", 2); data.Add("dog", 1); Console.WriteLine("cat - dog = ", data["cat"] - data["dog"]); > >
cat - dog = 1

Общие выводы. Var полезное ключевое слово. Оно похоже на #define или typedef языка C++. Мы используем var для краткости, это делает код проще для понимания. В некоторых случаях var может запутать, тогда используйте здравый смысл для организации кода.

[Ссылки]

1. var keyword site:dotnetperls.com.
2. var (справочник по C#) site:docs.microsoft.com.

Устаревшее ключевое слово «var»

Информация, приведенная в этой статье, полезна для понимания старых скриптов.

Мы не пишем современный код таким образом.

В самой первой главе про переменные мы ознакомились с тремя способами объявления переменных:

let и const ведут себя одинаково по отношению к лексическому окружению, области видимости.

Но var – это совершенно другой зверь, берущий своё начало с давних времён. Обычно var не используется в современных скриптах, но всё ещё может скрываться в старых.

Если в данный момент вы не работаете с подобными скриптами, вы можете пропустить или отложить прочтение данной главы, однако, есть шанс, что вы столкнётесь с var в будущем.

На первый взгляд, поведение var похоже на let . Например, объявление переменной:

function sayHi() < var phrase = "Привет"; // локальная переменная, "var" вместо "let" alert(phrase); // Привет >sayHi(); alert(phrase); // Ошибка: phrase не определена

…Однако, отличия всё же есть.

Для «var» не существует блочной области видимости

Область видимости переменных var ограничивается либо функцией, либо, если переменная глобальная, то скриптом. Такие переменные доступны за пределами блока.

if (true) < var test = true; // используем var вместо let >alert(test); // true, переменная существует вне блока if

Так как var игнорирует блоки, мы получили глобальную переменную test .

А если бы мы использовали let test вместо var test , тогда переменная была бы видна только внутри if :

if (true) < let test = true; // используем let >alert(test); // Error: test is not defined

Аналогично для циклов: var не может быть блочной или локальной внутри цикла:

for (var i = 0; i < 10; i++) < // . >alert(i); // 10, переменная i доступна вне цикла, т.к. является глобальной переменной

Если блок кода находится внутри функции, то var становится локальной переменной в этой функции:

function sayHi() < if (true) < var phrase = "Привет"; >alert(phrase); // срабатывает и выводит "Привет" > sayHi(); alert(phrase); // Ошибка: phrase не определена (видна в консоли разработчика)

Как мы видим, var выходит за пределы блоков if , for и подобных. Это происходит потому, что на заре развития JavaScript блоки кода не имели лексического окружения. Поэтому можно сказать, что var – это пережиток прошлого.

«var» допускает повторное объявление

Если в блоке кода дважды объявить одну и ту же переменную let , будет ошибка:

let user; let user; // SyntaxError: 'user' has already been declared

Используя var , можно переобъявлять переменную сколько угодно раз. Повторные var игнорируются:

var user = "Pete"; var user; // ничего не делает, переменная объявлена раньше // . нет ошибки alert(user); // Pete

Если дополнительно присвоить значение, то переменная примет новое значение:

var user = "Pete"; var user = "John"; alert(user); // John

«var» обрабатываются в начале запуска функции

Объявления переменных var обрабатываются в начале выполнения функции (или запуска скрипта, если переменная является глобальной).

Другими словами, переменные var считаются объявленными с самого начала исполнения функции вне зависимости от того, в каком месте функции реально находятся их объявления (при условии, что они не находятся во вложенной функции).

function sayHi() < phrase = "Привет"; alert(phrase); var phrase; >sayHi();

…Технически полностью эквивалентен следующему (объявление переменной var phrase перемещено в начало функции):

function sayHi() < var phrase; phrase = "Привет"; alert(phrase); >sayHi();

…И даже коду ниже (как вы помните, блочная область видимости игнорируется):

function sayHi() < phrase = "Привет"; // (*) if (false) < var phrase; >alert(phrase); > sayHi();

Это поведение называется «hoisting» (всплытие, поднятие), потому что все объявления переменных var «всплывают» в самый верх функции.

В примере выше if (false) условие никогда не выполнится. Но это никаким образом не препятствует созданию переменной var phrase , которая находится внутри него, поскольку объявления var «всплывают» в начало функции. Т.е. в момент присвоения значения (*) переменная уже существует.

Объявления переменных «всплывают», но присваивания значений – нет.

Это проще всего продемонстрировать на примере:

function sayHi() < alert(phrase); var phrase = "Привет"; >sayHi();

Строка var phrase = «Привет» состоит из двух действий:

  1. Объявление переменной var
  2. Присвоение значения в переменную = .

Объявление переменной обрабатывается в начале выполнения функции («всплывает»), однако присвоение значения всегда происходит в той строке кода, где оно указано. Т.е. код выполняется по следующему сценарию:

function sayHi() < var phrase; // объявление переменной срабатывает вначале. alert(phrase); // undefined phrase = "Привет"; // . присвоение - в момент, когда исполнится данная строка кода. >sayHi();

Поскольку все объявления переменных var обрабатываются в начале функции, мы можем ссылаться на них в любом месте. Однако, переменные имеют значение undefined до строки с присвоением значения.

В обоих примерах выше вызов alert происходил без ошибки, потому что переменная phrase уже существовала. Но её значение ещё не было присвоено, поэтому мы получали undefined .

IIFE

В прошлом, поскольку существовал только var , а он не имел блочной области видимости, программисты придумали способ её эмулировать. Этот способ получил название «Immediately-invoked function expressions» (сокращенно IIFE).

Это не то, что мы должны использовать сегодня, но, так как вы можете встретить это в старых скриптах, полезно понимать принцип работы.

IIFE выглядит следующим образом:

(function() < var message = "Hello"; alert(message); // Hello >)();

Здесь создаётся и немедленно вызывается Function Expression. Так что код выполняется сразу же и у него есть свои локальные переменные.

Function Expression обёрнуто в скобки (function <. >) , потому что, когда JavaScript встречает «function» в основном потоке кода, он воспринимает это как начало Function Declaration. Но у Function Declaration должно быть имя, так что такой код вызовет ошибку:

// Пробуем объявить и сразу же вызвать функцию function() < // ();

Даже если мы скажем: «хорошо, давайте добавим имя», – это не сработает, потому что JavaScript не позволяет вызывать Function Declaration немедленно.

// ошибка синтаксиса из-за скобок ниже function go() < >(); // 

Так что скобки вокруг функции – это трюк, который позволяет объяснить JavaScript, что функция была создана в контексте другого выражения, а значит, что это Function Expression: ей не нужно имя и её можно вызвать немедленно.

Помимо круглых скобок существуют и другие способы сообщить JavaScript, что мы имеем в виду Function Expression:

// Способы создания IIFE (function() < alert("Круглые скобки вокруг функции"); >)(); (function() < alert("Круглые скобки вокруг всего выражения"); >()); !function() < alert("Выражение начинается с логического оператора НЕ"); >(); +function() < alert("Выражение начинается с унарного плюса"); >();

Во всех перечисленных случаях мы объявляем Function Expression и немедленно запускаем его. Ещё раз отметим: в настоящее время необходимости писать подобный код нет.

Итого

Существует 2 основных отличия var от let/const :

  1. Переменные var не имеют блочной области видимости, они ограничены, как минимум, телом функции.
  2. Объявления (инициализация) переменных var производится в начале исполнения функции (или скрипта для глобальных переменных).

Есть ещё одно небольшое отличие, относящееся к глобальному объекту, мы рассмотрим его в следующей главе.

Эти особенности, как правило, не очень хорошо влияют на код. Блочная область видимости – это удобно. Поэтому много лет назад let и const были введены в стандарт и сейчас являются основным способом объявления переменных.

Зачем нужен var? И что он значит?

Ключевое слово var ("variable" означает "переменная") позволяет объявить переменную без явного указания типа, компилятор сам определит тип переменной по её значению.

9th Dec 2018, 4:51 PM
NezhnyjVampir

Алиса, var ,команда для создания переменной на языке JavaScript. Что такое переменная: Переменная - что-то вроде чемоданчика, в который можно положить что-то. Положить слово, цифру, или же объект. Что означает var? Var - сокращение от Variable (англ. Переменная)

6th Jan 2019, 10:37 AM
Andrew Andrew

Often have questions like this?

Learn more efficiently, for free:

C# vs R#: использование var вместо явного указания типа

В своей работе с замечательным дополнением ReSharper в Visual Studio я постоянно сталкивался с предложением вместо явного объявления типа переменных использовать объявления типа в неявной форме с использованием var. Сначала меня это несколько удивило, но я особо не обратил внимание. Но по прошествии некотрого времени такие предложения стали уже напрягать и я решил разобраться в чем же суть такой оптимизации.

Ответ был найден в блоге у создателей R# по этому адресу. По катом мой перевод статьи Ильи Рыженкова (Ilya Ryzhenkov).

  • использование 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 вместо явного указания типа? Лично для меня доводы приведенные в статье показались весомыми и даже правильными. Кто как думает?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *