const (компьютерное программирование) - const (computer programming)

В C , C ++ , D , JavaScript и Джулии языков программирования , сопзЬ является тип Классификатор : а ключевое слово применяется к типу данных , который указывает , что данные только для чтения. Хотя это можно использовать для объявления констант , const в семействе языков C отличается от аналогичных конструкций в других языках тем, что он является частью типа, и, следовательно, имеет сложное поведение в сочетании с указателями , ссылками, составными типами данных и проверкой типов.

Введение

При применении в объявлении объекта он указывает, что объект является константой : его значение не может быть изменено, в отличие от переменной . Это основное использование - объявление констант - имеет параллели во многих других языках.

Однако, в отличие от других языков, в семействе языков C const это часть типа , а не часть объекта . Например, в C, объявляет объект из типа - является частью типа, как если бы это были разобраны «(Int Const) х» - а в Ada , объявляет константу (вид объекта) из типа: это часть объекта , но не часть типа . int const x = 1;xint constconstX : constant INTEGER := 1_XINTEGERconstant

Это имеет два тонких результата. Во-первых, const может применяться к частям более сложного типа - например, int const * const x; объявляет постоянный указатель на постоянное целое число, в то время как int const * x; объявляет переменный указатель на постоянное целое число и int * const x; объявляет постоянный указатель на переменное целое число. Во-вторых, поскольку он const является частью типа, он должен соответствовать как часть проверки типа. Например, следующий код недействителен:

void f(int& x);
// ...
int const i;
f(i);

потому что аргумент f должен быть переменным целым числом, но i является постоянным целым числом. Это соответствие является формой корректности программы и известно как константная корректность . Это позволяет использовать форму программирования по контракту , когда функции указывают как часть своей сигнатуры типа , модифицируют ли они свои аргументы или нет, и можно ли их возвращаемое значение изменять или нет. Эта проверка типов в первую очередь представляет интерес для указателей и ссылок - а не для базовых типов значений, таких как целые числа, - но также для составных типов данных или шаблонных типов, таких как контейнеры . Это скрывается тем фактом, что const часто можно опускать из-за приведения типа (неявное преобразование типа ) и вызова C по значению (C ++ и D являются либо вызовом по значению, либо вызовом по ссылке).

Последствия

Идея постоянства не означает, что переменная, хранящаяся в памяти компьютера, не может быть записана. Скорее const -ness - это конструкция во время компиляции, которая указывает, что программист должен делать, не обязательно то, что он может делать. Однако следует отметить, что в случае предварительно определенные данные (например, char const * строковые литералы ), С const является часто недоступен для записи.

Отличие от констант

Хотя константа не меняет своего значения во время работы программы, объявленный объект const действительно может изменить свое значение во время работы программы. Типичный пример - регистры только для чтения во встроенных системах, такие как текущее состояние цифрового входа. Регистры данных для цифровых входов часто обозначаются как const и volatile . Содержимое этих регистров может измениться без каких-либо действий программы ( volatile ), но вы также не должны писать в них ( const ).

Другое использование

Кроме того, (нестатическая) функция-член может быть объявлена ​​как const . В этом случае this указатель внутри такой функции имеет тип, object_type const * а не просто тип object_type * . Это означает, что неконстантные функции для этого объекта нельзя вызывать изнутри такой функции, а также нельзя изменять переменные-члены . В C ++ переменная-член может быть объявлена ​​как mutable , что указывает на то, что это ограничение к ней не применяется. В некоторых случаях это может быть полезно, например, при кэшировании , подсчете ссылок и синхронизации данных . В этих случаях логическое значение (состояние) объекта не изменяется, но объект не является физически постоянным, поскольку его побитовое представление может измениться.

Синтаксис

В C, C ++ и D могут быть объявлены все типы данных, включая те, которые определены пользователем, const и константная корректность требует, чтобы все переменные или объекты были объявлены как таковые, если их не нужно изменять. Такое проактивное использование const делает значения «более понятными, отслеживаемыми и обоснованными» и, таким образом, повышает читаемость и понятность кода, а также упрощает работу в группах и сопровождение кода, поскольку оно передает информацию о предполагаемом использовании значения. Это может помочь компилятору, а также разработчику при рассмотрении кода. Это также может позволить оптимизирующему компилятору генерировать более эффективный код.

Простые типы данных

Для простых типов данных, не являющихся указателями, применить const квалификатор просто. По историческим причинам он может идти по обе стороны от некоторых типов (например, const char foo = 'a'; эквивалентен char const foo = 'a'; ). В некоторых реализациях использование const дважды (например, const char const или char const const ) генерирует предупреждение, но не ошибку.

Указатели и ссылки

Для типов указателей и ссылок значение const более сложное - может быть либо сам указатель, либо указанное значение, либо и то, и другое const . Кроме того, синтаксис может сбивать с толку. Указатель может быть объявлен как const указатель на доступное для записи значение, или как доступный для записи указатель на const значение, или как const указатель на const значение. const Указатель не может быть переведен в точку на другой объект из одного он изначально назначен, но он может быть использован для изменения значения , что она указывает на ( так называемый pointee ). Ссылочные переменные в C ++ - это альтернативный синтаксис для const указателей. С const другой стороны, указатель на объект можно переназначить, чтобы он указывал на другую ячейку памяти (которая должна быть объектом того же типа или конвертируемого типа), но его нельзя использовать для изменения памяти, на которую он указывает. к. const Указатель на const объект , также могут быть объявлены и ни один не может быть использован для изменения pointee , ни быть переназначены , чтобы указать на другой объект. Следующий код иллюстрирует эти тонкости:

void Foo( int * ptr,
          int const * ptrToConst,
          int * const constPtr,
          int const * const constPtrToConst )
{
    *ptr = 0; // OK: modifies the "pointee" data
    ptr  = NULL; // OK: modifies the pointer

    *ptrToConst = 0; // Error! Cannot modify the "pointee" data
    ptrToConst  = NULL; // OK: modifies the pointer

    *constPtr = 0; // OK: modifies the "pointee" data
    constPtr  = NULL; // Error! Cannot modify the pointer

    *constPtrToConst = 0; // Error! Cannot modify the "pointee" data
    constPtrToConst  = NULL; // Error! Cannot modify the pointer
}

Соглашение C

Следуя обычному соглашению C для объявлений, объявление следует за использованием, и * в указателе записывается указатель, указывающий на разыменование . Например, в объявлении int *ptr разыменованная форма *ptr - это int , а ссылочная форма ptr - это указатель на int . Таким образом const изменяется имя справа. Соглашение C ++ вместо этого заключается в том, чтобы связать * с типом, как в, int* ptr, и читать const как, изменяя тип слева. int const * ptrToConst таким образом, может быть прочитан как « *ptrToConst есть int const » (значение является постоянным) или « ptrToConst является int const * » (указатель является указателем на постоянное целое число). Таким образом:

int *ptr; // *ptr is an int value
int const *ptrToConst; // *ptrToConst is a constant (int: integer value)
int * const constPtr; // constPtr is a constant (int *: integer pointer)
int const * const constPtrToConst; // constPtrToConst is a constant (pointer)
                                   // as is *constPtrToConst (value)

Соглашение C ++

Следуя соглашению C ++ об анализе типа, а не значения, практическое правило - читать объявление справа налево. Таким образом, все, что находится слева от звезды, может быть идентифицировано как тип указателя, а все справа от звезды - это свойства указателя. Например, в нашем примере выше, он int const * может быть прочитан как доступный для записи указатель, который ссылается на незаписываемое целое число, и int * const может быть прочитан как незаписываемый указатель, который ссылается на доступное для записи целое число.

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

  1. найдите идентификатор, объявление которого вы хотите понять
  2. прочитайте как можно дальше вправо (то есть до конца объявления или до следующей закрывающей круглой скобки, в зависимости от того, что наступит раньше)
  3. вернитесь туда, где вы начали, и прочтите назад влево (то есть до начала объявления или до открытой круглой скобки, соответствующей закрывающей скобке, найденной на предыдущем шаге)
  4. когда вы дошли до начала объявления, все готово. Если нет, перейдите к шагу 2 за закрывающей круглой скобкой, которая была найдена последней.

Вот пример:

Часть выражения
double (**const (*fun(int))(double))[10]
Значение
(чтение вниз)
Идентификатор
                  fun
fun это ...
Читать вправо
                     (int))
функция ожидает int ...
Найдите совпадение (
                (*
возвращая указатель на ...
Продолжайте двигаться правильно
                           (double))
функция, ожидающая двойного ...
Найдите совпадение (
        (**const
возвращает постоянный указатель на
указатель на ...
Продолжайте двигаться правильно
                                    [10]
блоки по 10 ...
Читать слева
double
удваивается.

При чтении слева важно, чтобы вы читали элементы справа налево. Таким образом, an int const * становится указателем на const int, а не константным указателем на int .

В некоторых случаях C / C ++ позволяет const размещать ключевое слово слева от типа. Вот некоторые примеры:

const int *ptrToConst;            //identical to: int const *ptrToConst,
const int *const constPtrToConst; //identical to: int const *const constPtrToConst

Хотя C / C ++ допускает такие определения (которые близко соответствуют английскому языку при чтении определений слева направо), компилятор по-прежнему читает определения в соответствии с вышеупомянутой процедурой: справа налево. Но если поставить const перед тем, что должно быть постоянным, быстро появятся несоответствия между тем, что вы собираетесь написать, и тем, что компилятор решил, что вы написали. Рассмотрим указатели на указатели:

int **ptr;            // a pointer to a pointer to ints
int const **ptr       // a pointer to a pointer to constant int value
                      // (not a pointer to a constant pointer to ints)
int *const *ptr       // a pointer to a const pointer to int values
                      // (not a constant pointer to a pointer to ints)
int **const ptr       // a constant pointer to pointers to ints
                      // (ptr, the identifier, being const makes no sense)
int const **const ptr // a constant pointer to pointers to constant int values

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

int* a;          /* write: */     int *a;    // a is a pointer to an int
int* a, b;       // CONFUSING 
                 /* write: */     int *a, b; // a is a pointer to an int, 
                 //                             but b is a mere int
int* a, *b;      // UGLY: both a and b are pointers to ints
                 /* write: */     int *a, *b;

Во избежание этой проблемы в часто задаваемых вопросах Бьярна Страуструпа рекомендуется объявлять только одну переменную в строке при использовании соглашения C ++.

Те же соображения применимы к определению ссылок и ссылок rvalue:

int var = 22;
int const &refToConst = var;         // OK
int const& ref2 = var, ref3 = var;   // CONFUSING:
                                     // ref2 is a reference, but ref3 isn't:
                                     // ref3 is a constant int initialized with
                                     // var's value
int &const constRef = var;           // ERROR: as references can't change anyway.

// C++:
int&& rref = int(5), value = 10;     // CONFUSING:
                                     // rref is an rvalue reference, but value is
                                     // a mere int. 
                                     /* write: */ int &&rref = int(5), value = 10;

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

Параметры и переменные

const могут быть объявлены как в параметрах функции, так и в переменных ( статических или автоматических, включая глобальные или локальные). Интерпретация варьируется в зависимости от использования. const Статическая переменная (глобальная переменная или статическая локальная переменная) является постоянным, и может быть использовано для передачи данных , таких как математические константы, такие как double const PI = 3.14159 - реально больше, или общие параметры времени компиляции. const Автоматическая переменная (нестатический локальная переменная) означает , что одно назначение происходит, хотя другое значение может быть использовано каждый раз , когда , например int const x_squared = x * x . const Параметр передачи по ссылке означает , что упоминаемое значение не изменяются - это часть договора - в то время как const параметр в проходе по значению (или сам указатель, в проходе по ссылке) не добавляет ничего к интерфейсу (поскольку значение было скопировано), но указывает на то, что внутри функция не изменяет локальную копию параметра (это единственное присвоение). По этой причине некоторые предпочитают использовать const в параметрах только для передачи по ссылке, где он изменяет контракт, но не для передачи по значению, где он предоставляет реализацию.

C ++

Методы

Чтобы воспользоваться преимуществом контрактного подхода для определяемых пользователем типов (структур и классов), которые могут иметь методы, а также данные-члены, программист может пометить методы экземпляра, как const если бы они не изменяли элементы данных объекта. Применяя const спецификатор к методам экземпляра , таким образом , является существенным признаком для сопзЬ корректности, и не доступен во многих других объектно-ориентированных языков , таких как Java и C # или в Microsoft «s C ++ / CLI или расширений Managed для C ++ . Хотя const методы могут вызываться как объектами, так const и не const объектами, не const методы могут быть вызваны только const объектами. const Модификатора на метод экземпляра относится к объекту , на который указывает « this » указатель, который является неявный аргумент , передаваемый всех методов экземпляра. Таким образом, наличие const методов - это способ применить константную корректность к this аргументу неявного указателя, как и к другим аргументам.

Этот пример иллюстрирует:

class C
{
    int i;
public:
    int Get() const // Note the "const" tag
      { return i; }
    void Set(int j) // Note the lack of "const"
      { i = j; }
};

void Foo(C& nonConstC, C const& constC)
{
    int y = nonConstC.Get(); // Ok
    int x = constC.Get();    // Ok: Get() is const

    nonConstC.Set(10); // Ok: nonConstC is modifiable
    constC.Set(10);    // Error! Set() is a non-const method and constC is a const-qualified object
}

В приведенном выше коде неявный this указатель на "" Set() имеет тип " C *const "; тогда как " this " указатель на Get() имеет тип " C const *const ", указывающий, что метод не может изменить свой объект с помощью this указателя " ".

Часто программист предоставляет как метод, так const и не const метод с одним и тем же именем (но, возможно, совершенно по-разному) в классе, чтобы учесть оба типа вызывающих. Рассматривать:

class MyArray
{
    int data[100];
public:
    int &       Get(int i)       { return data[i]; }
    int const & Get(int i) const { return data[i]; }
};

void Foo( MyArray & array, MyArray const & constArray )
{
    // Get a reference to an array element
    // and modify its referenced value.

    array.Get( 5 )      = 42; // OK! (Calls: int & MyArray::Get(int))
    constArray.Get( 5 ) = 42; // Error! (Calls: int const & MyArray::Get(int) const)
}

const -Ness вызывающего объекта определяет , какая версия MyArray::Get() будет вызываться и , таким образом , вызывающему абоненту предоставляется ли или нет ссылки , с которыми он может манипулировать или только наблюдать за личные данные в объекте. Эти два метода технически имеют разные сигнатуры, так как их this указатели имеют разные типы, что позволяет компилятору выбрать правильный. (Возврат const ссылки на объект int вместо простого возврата int по значению может быть излишним во втором методе, но для произвольных типов можно использовать тот же метод, что и в стандартной библиотеке шаблонов .)

Лазейки для константной корректности

Есть несколько лазеек для чистой константной корректности в C и C ++. Они существуют в первую очередь для совместимости с существующим кодом.

Первый, который применим только к C ++, - это использование const_cast , которое позволяет программисту удалять const квалификатор, делая любой объект изменяемым. Необходимость удаления квалификатора возникает при использовании существующего кода и библиотек, которые нельзя изменить, но которые не являются корректными с константой. Например, рассмотрим этот код:

// Prototype for a function which we cannot change but which
// we know does not modify the pointee passed in.
void LibraryFunc(int* ptr, int size);

void CallLibraryFunc(int const * ptr, int size)
{
    LibraryFunc(ptr, size); // Error! Drops const qualifier

    int* nonConstPtr = const_cast<int*>(ptr); // Strip qualifier
    LibraryFunc(nonConstPtr, size);  // OK
}

Однако любая попытка изменить объект, который сам объявлен const с помощью константного приведения, приводит к неопределенному поведению в соответствии со стандартом ISO C ++. В приведенном выше примере, если ptr ссылка на глобальную, локальную переменную или переменную-член, объявленную как const , или объект, выделенный в куче new int const , является правильным, только если LibraryFunc действительно не изменяет значение, на которое указывает ptr .

В языке C есть потребность в лазейке, потому что существует определенная ситуация. Переменные со статической продолжительностью хранения могут быть определены с начальным значением. Однако инициализатор может использовать только константы, такие как строковые константы и другие литералы, и ему не разрешается использовать непостоянные элементы, такие как имена переменных, независимо от того, объявлены ли элементы инициализатора const или нет, или объявлена ​​ли статическая переменная длительности const или нет. Существует непереносимый способ инициализировать const переменную со статической продолжительностью хранения. Тщательно построив приведение типов в левой части более позднего присваивания, const можно записать переменную, эффективно удаляя const атрибут и «инициализируя» его непостоянными элементами, такими как другие const переменные и тому подобное. Запись в const переменную таким способом может работать как задумано, но вызывает неопределенное поведение и серьезно противоречит константной корректности:

size_t const    bufferSize = 8*1024;
size_t const    userTextBufferSize;  //initial value depends on const bufferSize, can't be initialized here

...

int setupUserTextBox(textBox_t *defaultTextBoxType, rect_t *defaultTextBoxLocation)
{
    *(size_t*)&userTextBufferSize = bufferSize - sizeof(struct textBoxControls);  // warning: might work, but not guaranteed by C
    ...
}

Еще одна лазейка относится как к C, так и к C ++. В частности, языки диктуют, что указатели на элементы и ссылки должны быть «неглубокими» по отношению к const их владельцам, то есть содержащий объект, который const имеет все const члены, за исключением тех, кто указывает на члены (и рефери), по-прежнему изменяемыми. Для иллюстрации рассмотрим этот код C ++:

struct S
{
    int val;
    int *ptr;
};

void Foo(S const & s)
{
    int i  = 42;
    s.val  = i;  // Error: s is const, so val is a const int
    s.ptr  = &i; // Error: s is const, so ptr is a const pointer to int
    *s.ptr = i;  // OK: the data pointed to by ptr is always mutable,
                 //     even though this is sometimes not desirable
}

Хотя объект, s переданный в, Foo() является константой, что делает все его члены постоянными, объект, доступный через указатель, по- s.ptr прежнему может быть const изменен , хотя это может быть нежелательно с точки зрения правильности, поскольку он s может принадлежать только объекту. По этой причине Мейерс утверждает, что значение по умолчанию для указателей и ссылок на элементы должно быть «глубоким» const , что может быть переопределено mutable квалификатором, если указатель не принадлежит контейнеру, но эта стратегия создаст проблемы совместимости с существующим кодом. Таким образом, по историческим причинам эта лазейка остается открытой в C и C ++.

Последнюю лазейку можно закрыть с помощью класса, скрывающего указатель за const -правильным интерфейсом, но такие классы либо не поддерживают обычную семантику копирования из const объекта (подразумевая, что содержащий класс не может быть скопирован обычной семантикой), либо разрешить другие лазейки, разрешив удаление const -ness посредством непреднамеренного или преднамеренного копирования.

Наконец, несколько функций в стандартной библиотеке C нарушают константную корректность, поскольку они принимают const указатель на символьную строку и возвращают не- const указатель на часть той же строки. strtol и strchr входят в число этих функций. Некоторые реализации стандартной библиотеки C ++, такие как Microsoft, пытаются закрыть эту лазейку, предоставляя две перегруженные версии некоторых функций: « const » версию и «не- const » версию.

Проблемы

Использование системы типов для выражения постоянства приводит к различным сложностям и проблемам и, соответственно, подвергалось критике и не принималось за пределами узкого семейства C, включая C, C ++ и D. Java и C #, на которые сильно влияют C и C ++, оба явно отклонили const квалификаторы типа -style, вместо этого выражая постоянство ключевыми словами, которые применяются к идентификатору ( final в Java const и readonly C #). Даже в C и C ++ использование const сильно различается: одни проекты и организации используют его последовательно, а другие избегают.

strchr проблема

const Типа классификатор вызывает трудности , когда логика функции является агностиком ли его вход является постоянным или нет, но возвращает значение , которое должно быть того же типа , квалифицированным в качестве входных данных. Другими словами, для этих функций, если вход является константой (с квалификацией const), возвращаемое значение также должно быть, но если вход является переменным (не const квалифицированным), возвращаемое значение также должно быть. Поскольку сигнатуры типа этих функций различаются, для этого требуются две функции (или потенциально больше, в случае нескольких входов) с одинаковой логикой - это форма общего программирования .

Эта проблема возникает даже для простых функций в стандартной библиотеке C, в частности strchr ; Ричи приписывает это наблюдение Тому Плему в середине 1980-х годов. strchr Функция находит символ в строке; формально он возвращает указатель на первое вхождение символа c в строке s , а в классическом C (K&R C) его прототипом является:

char *strchr(char *s, int c);

strchr Функция не изменяет входной строки, но возвращаемое значение часто используется вызывающим для изменения строки, такие как:

if (p = strchr(q, '/'))
    *p = ' ';

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

В C ++ это делается через перегрузку функций , обычно реализуемую с помощью шаблона , в результате чего const создаются две функции, так что возвращаемое значение имеет тот же -квалифицированный тип, что и вход:

char* strchr(char* s, int c);
char const* strchr(char const* s, int c);

Их, в свою очередь, можно определить с помощью шаблона:

template <T>
T* strchr(T* s, int c) { ... }

В D это обрабатывается с помощью inout ключевого слова, которое действует как подстановочный знак для const, неизменяемого или неквалифицированного (переменной), что дает:

inout(char)* strchr(inout(char)* s, int c);

Однако в C ни то, ни другое невозможно, поскольку C не имеет перегрузки функций, а вместо этого это обрабатывается с помощью единственной функции, где вход постоянен, но выход доступен для записи:

char *strchr(char const *s, int c);

Это позволяет использовать идиоматический код C, но удаляет квалификатор const, если ввод действительно квалифицирован как const, что нарушает безопасность типов. Это решение было предложено Ричи и впоследствии принято. Это отличие - один из недостатков совместимости C и C ++ .

D

В версии 2 языка программирования D существуют два ключевых слова, относящиеся к const. immutable Ключевое слово означает , что данные не могут быть изменены с помощью каких - либо ссылок. const Ключевое слово обозначает не-изменчивый вид изменяемых данных. В отличие от C ++ const , D const и immutable являются «глубокие» или транзитивно , и все , что достижимы через const или immutable объект const или immutable соответственно.

Пример константы и неизменяемости в D

int[] foo = new int[5];  // foo is mutable.
const int[] bar = foo;   // bar is a const view of mutable data.
immutable int[] baz = foo;  // Error:  all views of immutable data must be immutable.

immutable int[] nums = new immutable(int)[5];  // No mutable reference to nums may be created.
const int[] constNums = nums;  // Works.  immutable is implicitly convertible to const.
int[] mutableNums = nums;  // Error:  Cannot create a mutable view of immutable data.

Пример транзитивной или глубокой константы в D

class Foo {
    Foo next;
    int num;
}

immutable Foo foo = new immutable(Foo);
foo.next.num = 5;  // Won't compile.  foo.next is of type immutable(Foo).
                   // foo.next.num is of type immutable(int).

История

const был представлен Бьярном Страуструпом в языке C с классами , предшественником C ++ , в 1981 году и первоначально назывался readonly . Что касается мотивации, Страуструп пишет:

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

Первое использование в качестве альтернативы макросам с заданной областью и типизацией аналогично выполнялось для макросов, подобных функциям, через inline ключевое слово. Постоянные указатели и * const обозначения были предложены Деннисом Ричи и поэтому приняты.

const затем был принят в C как часть стандартизации и появился в C89 (и последующих версиях) вместе с другим квалификатором типа volatile . На noalias заседании комитета X3J11 в декабре 1987 г. был предложен дополнительный квалификатор , но он был отклонен; в конечном итоге его цель была достигнута с помощью restrict ключевого слова в C99 . Ричи не очень поддерживал эти дополнения, утверждая, что они не «несут их вес», но в конечном итоге не выступал за их исключение из стандарта.

Впоследствии D унаследован const от C ++, где он известен как конструктор типа (а не квалификатор типа ), и добавил два дополнительных конструктора типа immutable и inout для обработки связанных вариантов использования.

Другие языки

Другие языки не следуют C / C ++ в части постоянства типа, хотя они часто имеют внешне похожие конструкции и могут использовать const ключевое слово. Обычно это используется только для констант (постоянных объектов).

В C # есть const ключевое слово, но с радикально другой и более простой семантикой: оно означает константу времени компиляции и не является частью типа.

В Nim есть const ключевое слово, аналогичное ключевому слову C #: он также объявляет константу времени компиляции, а не является частью типа. Однако в Nim константу можно объявить из любого выражения, которое можно вычислить во время компиляции. В C # только встроенные типы C # могут быть объявлены как const ; Пользовательские типы, включая классы, структуры и массивы, не могут быть const .

В Java нет const - вместо этого есть final , что может быть применено к объявлениям локальных «переменных» и применяется к идентификатору, а не к типу. Он имеет другое объектно-ориентированное использование для членов объекта, которое является источником имени.

Спецификация языка Java рассматривает const как зарезервированное ключевое слово, т. Е. Такое , которое нельзя использовать как идентификатор переменной, но не присваивает ему семантику: это зарезервированное слово (его нельзя использовать в идентификаторах), но не ключевое слово (оно не имеет специального имея в виду). Считается, что ключевое слово было зарезервировано, чтобы позволить расширение языка Java включить const методы в стиле C ++ и указатель на const тип. Билет запроса на расширение для реализации const корректности существует в Java Community Process , но был закрыт в 2005 году на том основании, что его невозможно было реализовать обратно совместимым способом.

Современная Ada 83 независимо друг от друга имела понятие постоянного объекта и constant ключевого слова, при этом входные параметры и параметры цикла были неявно постоянными. Здесь constant - свойство объекта, а не его типа.

В JavaScript есть const объявление, определяющее переменную с блочной областью видимости, которую нельзя переназначить или повторно объявить. Он определяет доступную только для чтения ссылку на переменную, которую нельзя переопределить, но в некоторых ситуациях значение самой переменной потенциально может измениться, например, если переменная ссылается на объект и его свойство изменяется.

Смотрите также

Ноты

Рекомендации

внешние ссылки