İçeriğe geç

Fonksiyonlar

Bir fonksiyon, tekrar kullanılabilir bir kod bloğudur. Bir isim verir, isteğe bağlı olarak veri aktarır ve isteğe bağlı olarak veri alırsınız.

dönüşTipi fonksiyonAdı(parametreTipi parametreAdı, ...) {
// gövde
return değer;
}
int add(int a, int b) {
return a + b;
}
  • Dönüş tipi (int, float, bool, string, void, vb.) zorunludur ve en başta gelir
  • Ardından isim gelir
  • Parametreler parantez içinde, her biri bir tip ve bir isimle yazılır
  • Gövde { } içinde yer alır
  • return çağırana bir değer gönderir

Bir fonksiyon hiçbir şey döndürmüyorsa void kullanın:

void greet(string name) {
print("Hello");
print(name);
// return gerekmez
}
int main() {
int result = add(3, 4);
print(result); // 7
greet("saQut"); // "Hello" "saQut"
return 0;
}

İlkel tipler (int, float, bool, byte) için fonksiyon, değerin bir kopyasını alır. Fonksiyon içinde değiştirmek çağıranı etkilemez:

void change(int x) {
x = 100; // sadece yerel kopyayı değiştirir
}
int main() {
int a = 5;
change(a);
print(a); // 5, değişmedi
return 0;
}

Bileşik tipler (struct, dizi, string) için fonksiyon bir referans alır: içeriği değiştirmek çağıranın verisini etkiler.

Parametreleri virgülle ayırın:

int multiply(int a, int b, int c) {
return a * b * c;
}
int main() {
print(multiply(2, 3, 4)); // 24
return 0;
}

Fonksiyonun herhangi bir yerinden dönebilirsiniz:

int divide(int a, int b) {
if (b == 0) {
return 0; // erken dönüş, koruma koşulu
}
return a / b;
}

Bir fonksiyon kendini çağırabilir:

int factorial(int n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
int main() {
print(factorial(5)); // 120
return 0;
}
void hanoi(int n, int from, int to, int aux) {
if (n == 0) { return; }
hanoi(n - 1, from, aux, to);
print(from);
print(to);
hanoi(n - 1, aux, to, from);
}
int main() {
hanoi(3, 1, 3, 2);
return 0;
}

Her program main() ile başlar. Mutlaka bulunmalı ve int döndürmelidir:

int main() {
// kodunuz
return 0;
}

0 döndürmek genellikle başarılı anlamına gelir. Sıfırdan farklı değerler bir hata olduğunu belirtir.

Yukarıdaki “yerel kopya” kuralı ilkel tipler için geçerlidir. Bileşik tipler (struct, dizi, string) referans ile aktarılır: fonksiyon aynı alt veriyi alır, dolayısıyla yaptığı değişiklikler çağıran tarafından görülür:

void fill(int[] a) {
a[0] = 99; // çağıranın dizisini değiştirir
}
int main() {
int[] x = [1, 2, 3];
fill(x);
print(x[0]); // 99, değişiklik kalıcı oldu
return 0;
}

Aynı durum struct’lar için de geçerlidir: bir alanı değiştiren fonksiyon, çağıranın struct’ını da değiştirir. (Bkz. referans anlamsallığı.) Bu verimlidir (kopyalama yoktur) ancak bir fonksiyonun kendisine aktarılanı değiştirebileceği anlamına gelir. Bunu istemiyorsanız, fonksiyon parametresine yazmaktan kaçınmalıdır.

Bir fonksiyon bir struct döndürdüğünde, çağıran dönen değere bir referans alır:

struct Point { int x; int y; }
Point origin() {
Point p;
p.x = 0;
p.y = 0;
return p;
}

Kısıtlama: dizi dönüş tipleri desteklenmez. Şu anda int[] makeList() { ... } yazamazsınız: dizi dönüş tipi ayrıştırılamaz. Geçici çözüm, diziyi bir struct içine sarıp onu döndürmektir:

struct IntList { int[] items; }
IntList range() {
IntList r;
r.items = [1, 2, 3];
return r;
}

Alternatif olarak, diziyi bir referans parametresi olarak alıp yerinde doldurabilirsiniz (yukarıdaki fill örneğine bakın).

  • Aşırı yükleme (overloading) yok. Bir fonksiyon adı tek bir fonksiyona işaret eder; aynı isimle farklı parametrelere sahip iki fonksiyon tanımlayamazsınız.
  • Varsayılan parametre değeri yok. Her parametre açıkça belirtilmelidir; argüman sayısı eşleşmelidir (aksi halde E008 alırsınız).
  • İç içe fonksiyon yok. Fonksiyonlar en üst düzeyde tanımlanır, asla başka bir fonksiyonun gövdesi içinde tanımlanamaz (bu E011 hatasıdır).
  • Derin özyineleme çağrı yığınını kullanır. Her çağrı bir çerçeve ekler; aşırı derin özyineleme yığını tüketebilir, bu yüzden çok büyük girdiler için yinelemeli (iterative) bir sürümü tercih edin.
int add(int a, int b) { return a + b; }
int main() {
add(1, 2, 3); // HATA, 3 argüman, fonksiyon 2 bekliyor
return 0;
}
int getValue() {
return 1.5; // HATA, float döndürüyor, int olarak tanımlandı
}
int main() {
foo(); // HATA, 'foo' tanımlı değil
return 0;
}

(Ancak ileri referanslar çalışır: iki geçişli sembol toplayıcı sayesinde fonksiyon aynı dosyada daha sonra tanımlanmışsa sorun olmaz.)

  • İlgili verileri struct ile gruplandırın
  • Dizileri saklamak için dizileri kullanın