Programowanie D - funkcje
W tym rozdziale opisano funkcje używane w programowaniu D.
Definicja funkcji w D
Podstawowa definicja funkcji składa się z nagłówka funkcji i treści funkcji.
Składnia
return_type function_name( parameter list ) {
body of the function
}
Oto wszystkie części funkcji -
Return Type- Funkcja może zwrócić wartość. Plikreturn_typejest typem danych wartości zwracanej przez funkcję. Niektóre funkcje wykonują żądane operacje bez zwracania wartości. W tym przypadku return_type jest słowem kluczowymvoid.
Function Name- To jest rzeczywista nazwa funkcji. Nazwa funkcji i lista parametrów razem tworzą podpis funkcji.
Parameters- Parametr działa jak symbol zastępczy. Gdy funkcja jest wywoływana, przekazujesz wartość do parametru. Ta wartość jest określana jako rzeczywisty parametr lub argument. Lista parametrów odnosi się do typu, kolejności i liczby parametrów funkcji. Parametry są opcjonalne; to znaczy, funkcja może nie zawierać żadnych parametrów.
Function Body - Treść funkcji zawiera zbiór instrukcji, które definiują, co robi funkcja.
Wywołanie funkcji
Możesz wywołać funkcję w następujący sposób -
function_name(parameter_values)
Typy funkcji w D
Programowanie D obsługuje szeroki zakres funkcji i są one wymienione poniżej.
- Czyste funkcje
- Funkcje Nothrow
- Funkcje ref
- Funkcje automatyczne
- Funkcje wariadyczne
- Funkcje Inout
- Funkcje właściwości
Różne funkcje opisano poniżej.
Czyste funkcje
Czyste funkcje to funkcje, które nie mogą uzyskać dostępu do globalnego lub statycznego, zmiennego stanu, poza swoimi argumentami. Może to umożliwić optymalizacje oparte na fakcie, że czysta funkcja gwarantuje, że nie zmutuje niczego, co nie zostanie do niej przekazane, aw przypadkach, gdy kompilator może zagwarantować, że czysta funkcja nie może zmienić swoich argumentów, może zapewnić pełną, funkcjonalną czystość, że jest gwarancją, że funkcja zawsze zwróci ten sam wynik dla tych samych argumentów).
import std.stdio;
int x = 10;
immutable int y = 30;
const int* p;
pure int purefunc(int i,const char* q,immutable int* s) {
//writeln("Simple print"); //cannot call impure function 'writeln'
debug writeln("in foo()"); // ok, impure code allowed in debug statement
// x = i; // error, modifying global state
// i = x; // error, reading mutable global state
// i = *p; // error, reading const global state
i = y; // ok, reading immutable global state
auto myvar = new int; // Can use the new expression:
return i;
}
void main() {
writeln("Value returned from pure function : ",purefunc(x,null,null));
}
Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -
Value returned from pure function : 30
Funkcje Nothrow
Funkcje Nothrow nie zgłaszają żadnych wyjątków pochodzących z klasy Exception. Funkcje nothrow są kowariantne z funkcjami rzucającymi.
Nothrow gwarantuje, że funkcja nie emituje żadnego wyjątku.
import std.stdio;
int add(int a, int b) nothrow {
//writeln("adding"); This will fail because writeln may throw
int result;
try {
writeln("adding"); // compiles
result = a + b;
} catch (Exception error) { // catches all exceptions
}
return result;
}
void main() {
writeln("Added value is ", add(10,20));
}
Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -
adding
Added value is 30
Funkcje ref
Funkcje ref pozwalają funkcjom zwracać się przez odniesienie. Jest to analogiczne do parametrów funkcji ref.
import std.stdio;
ref int greater(ref int first, ref int second) {
return (first > second) ? first : second;
}
void main() {
int a = 1;
int b = 2;
greater(a, b) += 10;
writefln("a: %s, b: %s", a, b);
}
Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -
a: 1, b: 12
Funkcje automatyczne
Funkcje automatyczne mogą zwracać wartość dowolnego typu. Nie ma ograniczeń dotyczących zwracanego typu. Prosty przykład funkcji auto typu jest podany poniżej.
import std.stdio;
auto add(int first, double second) {
double result = first + second;
return result;
}
void main() {
int a = 1;
double b = 2.5;
writeln("add(a,b) = ", add(a, b));
}
Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -
add(a,b) = 3.5
Funkcje wariadyczne
Funkcje variadiac to te funkcje, w których liczba parametrów funkcji jest określana w czasie wykonywania. W C istnieje ograniczenie związane z posiadaniem co najmniej jednego parametru. Ale w programowaniu D nie ma takiego ograniczenia. Poniżej przedstawiono prosty przykład.
import std.stdio;
import core.vararg;
void printargs(int x, ...) {
for (int i = 0; i < _arguments.length; i++) {
write(_arguments[i]);
if (_arguments[i] == typeid(int)) {
int j = va_arg!(int)(_argptr);
writefln("\t%d", j);
} else if (_arguments[i] == typeid(long)) {
long j = va_arg!(long)(_argptr);
writefln("\t%d", j);
} else if (_arguments[i] == typeid(double)) {
double d = va_arg!(double)(_argptr);
writefln("\t%g", d);
}
}
}
void main() {
printargs(1, 2, 3L, 4.5);
}
Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -
int 2
long 3
double 4.5
Funkcje Inout
Inout może być używany zarówno dla parametrów, jak i typów zwracanych funkcji. Jest jak szablon dla zmiennych, stałych i niezmiennych. Atrybut zmienności jest wywnioskowany z parametru. Oznacza, że inout przenosi wydedukowany atrybut zmienności do typu zwracanego. Poniżej przedstawiono prosty przykład pokazujący, jak zmienia się zmienność.
import std.stdio;
inout(char)[] qoutedWord(inout(char)[] phrase) {
return '"' ~ phrase ~ '"';
}
void main() {
char[] a = "test a".dup;
a = qoutedWord(a);
writeln(typeof(qoutedWord(a)).stringof," ", a);
const(char)[] b = "test b";
b = qoutedWord(b);
writeln(typeof(qoutedWord(b)).stringof," ", b);
immutable(char)[] c = "test c";
c = qoutedWord(c);
writeln(typeof(qoutedWord(c)).stringof," ", c);
}
Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -
char[] "test a"
const(char)[] "test b"
string "test c"
Funkcje właściwości
Właściwości pozwalają na używanie funkcji składowych, takich jak zmienne składowe. Używa słowa kluczowego @property. Właściwości są połączone z pokrewną funkcją, która zwraca wartości na podstawie wymagań. Poniżej przedstawiono prosty przykład właściwości.
import std.stdio;
struct Rectangle {
double width;
double height;
double area() const @property {
return width*height;
}
void area(double newArea) @property {
auto multiplier = newArea / area;
width *= multiplier;
writeln("Value set!");
}
}
void main() {
auto rectangle = Rectangle(20,10);
writeln("The area is ", rectangle.area);
rectangle.area(300);
writeln("Modified width is ", rectangle.width);
}
Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -
The area is 200
Value set!
Modified width is 30