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 intO 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:
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
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;Typedefs podem especificar um inicializador padrão diferente do inicializador padrão do tipo subjacente:
void foo(int x) { . }
void foo(myint m) { . }
.
myint b;
foo(b); // chama foo(myint)
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()Portanto, alguém deveria usar inicializadores void somente como um último recurso quando otimizando código crítico.
{
int x = void;
writefln(x); // imprimirá lixo
}