www.digitalmars.com
Last update Wed Aug 30 22:04:58 2006

Declarações

Declaração:
typedef Decl
alias Decl
Decl
Decl:
StorageClasses Decl
BasicType Declarators ;
BasicType Declarator FunctionBody
AutoDeclaration
Declarators:
DeclaratorInitializer
DeclaratorInitializer , DeclaratorIdentifierList
DeclaratorInitializer:
Declarator
Declarator = Initializer
DeclaratorIdentifierList:
DeclaratorIdentifier
DeclaratorIdentifier , DeclaratorIdentifierList
DeclaratorIdentifier:
Identifier
Identifier = Initializer
BasicType:
bool
byte
ubyte
short
ushort
int
uint
long
ulong
char
wchar
dchar
float
double
real
ifloat
idouble
ireal
cfloat
cdouble
creal
void
.IdentifierList
IdentifierList
Typeof
Typeof . IdentifierList
BasicType2:
*
[ ]
[ Expression ]
[ Type ]
delegate Parameters
function Parameters
Declarator:
BasicType2 Declarator
Identifier
() Declarator
Identifier DeclaratorSuffixes
() Declarator DeclaratorSuffixes
DeclaratorSuffixes:
DeclaratorSuffix
DeclaratorSuffix DeclaratorSuffixes
DeclaratorSuffix:
[ ]
[ Expression ]
[ Type ]
Parameters
IdentifierList:
Identifier
Identifier . IdentifierList
TemplateInstance
TemplateInstance . IdentifierList
Typeof:
typeof ( Expression )
StorageClasses:
StorageClass
StorageClass StorageClasses
StorageClass:
abstract
auto
const
deprecated
extern
final
override
static
synchronized
Type:
BasicType
BasicType Declarator2
Declarator2:
BasicType2 Declarator2
( Declarator2 )
( Declarator2 ) DeclaratorSuffixes
Parameters:
( ParameterList )
( )
ParameterList:
Parameter
Parameter , ParameterList
Parameter ...
...
Parameter:
Declarator
Declarator = AssignExpression
InOut Declarator
InOut Declarator = AssignExpression
InOut:
in
out
inout
lazy
Initializer:
void
AssignExpression
ArrayInitializer
StructInitializer
ArrayInitializer:
[ ArrayMemberInitializations ]
[ ]
ArrayMemberInitializations:
ArrayMemberInitialization
ArrayMemberInitialization ,
ArrayMemberInitialization , ArrayMemberInitializations
ArrayMemberInitialization:
AssignExpression
AssignExpression : AssignExpression
StructInitializer:
{ }
{ StructMemberInitializers }
StructMemberInitializers:
StructMemberInitializer
StructMemberInitializer ,
StructMemberInitializer , StructMemberInitializers
StructMemberInitializer:
AssignExpression
Identifier : AssignExpression
AutoDeclaration:
StorageClasses Identifier = AssignExpression ;

Sintaxe de Declaração   

A sintaxe de declaração geralmente é lida da direita para esquerda:

int x; // x é um int
int* x; // x ié um ponteiro para int
int** x; // x é um ponteiro para um pontairo para int
int[] x; // x é um array de ints
int*[] x; // x é um array de ponteiros para ints
int[]* x; // x é um ponteiro para um array de ints

Arrays também são lidos da direita para esquerda:

int[3] x; // x é um array de 3 ints
int[3][5] x; // x é um array de 5 arrays de 3 ints
int[3]*[5] x; // x é um array de 5 ponteiros para arrays de 3 ints

Ponteiros para função são declarados usando a palavra reservada function:

int function(char) x; // x é um ponteiro para uma função que aceita um 
// argumento char e retorna um int
int function(char)[] x; // x é um array d ponteiros para funções
// que aceitam um argumento char e retornam um int

Declarações de array estilo C podem ser usadas como alternativa:

int x[3]; // x é um array de 3 ints
int x[3][5]; // x é um array de 3 arrays de 5 ints
int (*x[5])[3]; // x é um array de 5 ponteiros para arrays de 3 ints
int (*x)(char); // x é um ponteiro para uma função que aceita um argumento
// char e retorna um int
int (*[] x)(char); // x é um array de ponteiros para funções que
// aceitam um argumento char e retornam um int

Em uma declaração de múltiplos símbolos, todas as declarações devem ser do mesmo tipo:

int x,y; // x e y são ints
int* x,y; // x e y são ponteiros para ints
int x,*y; // erro, múltiplos tipos
int[] x,y; // x e y são array de ints
int x[],y; // erro, múltiplos tipos

Inferência Imlícita de Tipo

Se uma declaração começa com uma StorageClass e tem um Initializer cujo tipo pode ser inferido, o tipo na declaração pode ser omitido.
static x = 3; // x é do tipo int
auto y = 4u; // y é do tipo uint
auto s = "string"; // s é do tipo char[6]

class C { ... }

auto c = new C(); // c é um controle para uma instância de C
O Initializer não pode conter referêcias adiantadas (essa restrição pode ser removida no futuro). O tipo inferenciado implicitamente é limitado estaticamente à declaração em tempo de compilação, não em tempo de execução. Uma inferência implícita de tipo para uma referência de classe não é uma declaração auto, mesmo se a classe de armazenamento auto for usada:
class C { ... }

auto c = new C(); // c não é RAII
auto C d = new C(); // c é automaticamente destruída no fim de seu escopo

Definição de Tipo

Tipos fortes podem ser introduzidos com typedef. Tipos fortes são semanticamente um tipo distinto para o sistema de checagem de tipo, para sobrecarga de funções e para o depurador.

typedef int myint;

void foo(int x) { . }
void foo(myint m) { . }

.
myint b;
foo(b); // chama foo(myint)
Typedefs podem especificar um inicializador padrão diferente do inicializador padrão do tipo subjacente:
typedef int myint = 7;
myint m; // inicializado para 7

Apeliando um Tipo

Algumas vezes é conveniente usar um apelido para um tipo, como um atalho para um tipo longo ou complexo como um ponteiro para uma função. Em D, isso é feito com a declaração de apelido:

alias abc.Foo.bar myint;

Tipos abelidados são semanticamente identicos aos tipos que os originaram. O depurador não pode distinguir entre eles, e não há diferenças quando se preocupando com sobrecarga de funções. Por exemplo:

alias int myint;

void foo(int x) { . }
void foo(myint m) { . } // erro, múltiplas definições da função foo

Apelidos de tipo são equivalentes ao typedef em C.

Declarações de Apelido

Um símbolo pode ser declarado como um apelido de outro símbolo. Por exemplo:

import string;

alias string.strlen mylen;
...
int len = mylen("hello"); // agora chama string.strlen()

As seguintes declarações de apelido são válidas:

template Foo2(T) { alias T t; }
alias Foo2!(int) t1;
alias Foo2!(int).t t2;
alias t1.t t3;
alias t2 t4;

t1.t v1; // v1 é do tipo int
t2 v2; // v2 é do tipo int
t3 v3; // v3 é do tipo int
t4 v4; // v4 é do tipo int

Símbolos apelidados são úteis como um atalho para um nome muito longo, ou como um modo de redirecionar referências de um símbolo para outro:

version (Win32)
{
alias win32.foo myfoo;
}
version (linux)
{
alias linux.bar myfoo;
}

Apelidos podem ser usados para 'importar' um símbolo de uma importação no escopo atual:

alias string.strlen strlen;

Apelidos podem também 'importar' um conjunto de funções sobrecarregadas, que podem ser sobrecarregadas com funções no escopo atual:

class A {
int foo(int a) { return 1; }
}

class B : A {
int foo( int a, uint b ) { return 2; }
}

class C : B {
int foo( int a ) { return 3; }
alias B.foo foo;
}

class D : C {
}


void test()
{
D b = new D();
int i;

i = b.foo(1, 2u); // chama B.foo
i = b.foo(1); // chama C.foo
}

Nota: Apelidos de tipos podem algumas vezes parecer indistinguíveis de declarações de apelido:

alias foo.bar abc; // is isso é um tipo ou um símbolo?

A distinção é feita na fase da análise semântica.

Apelidos não podem ser usados para expressões:

struct S { static int i; }
S s;

alias s.i a; // ilegal, s.i é uma expressão
alias S.i b; // ok
b = 4; // ajusta S.i para 4

Declarações Externas

Declarações de variáveis com a classe de armazenamento extern não são alocadas armazenadas dentro do módulo. Elas devem ser definidas em algum outro arquivo objeto com um nome que é linkado. A utilidade primária disso é conectar com variáveis declaradas globalmente em arquivos C.

typeof

Typeof é um jeito de especificar um tipo baseado no tipo de uma expressão. Por exemplo:

void func(int i)
{
typeof(i) j; // j é do tipo int
typeof(3 + 6.0) x; // x é do tipo double
typeof(1)* p; // p é do tipo ponteiro int
int[typeof(p)] a; // a é do tipo int[int*]

printf("%d\n", typeof('c').sizeof); // imprime 1
double c = cast(typeof(1.0))j; // molda j para double
}

Expression não é avaliada, apenas o tipo gerado:

void func()
{ int i = 1;
typeof(++i) j; // j é declarado para ser int, i não é incrementado
printf("%d\n", i); // imprime 1
}

Há dois casos especiais: typeof(this) gerará o tipo que this seria em uma função membro não-estática, mesmo se não em uma função membro. Analogamente, typeof(super) gerará o tipo que super seria em uma função membro não-estática.

class A { }

class B : A
{
typeof(this) x; // x é declarado para ser um B
typeof(super) y; // y é declarado para ser um A
}

struct C
{
typeof(this) z; // z é declarado para ser um C*
typeof(super) q; // erro, nenhuma super classe para a estrutura C
}

typeof(this) r; // erro, nenhuma classe ou estrutura envolvendo

Onde Typeof é mais útil é em escrever código genérico de gabarito.

Inicializações Vazias

Normalmente, variáveis são inicializadas ou com um Initializer explícito ou são ajustadas para o valor padrão para o tipo da variável. Se o Initializer é void, porém, a variável não é inicializada. Se esse valor for usado antes de ser ajustadom, comportamento indefinido do programa será resultado.
void foo()
{
int x = void;
writefln(x); // imprimirá lixo
}
Portanto, alguém deveria usar inicializadores void somente como um último recurso quando otimizando código crítico.