Fungsi
Fungsi-fungsi banyak digunakan dalam kode Cairo. Anda sudah melihat salah satu fungsi yang paling penting dalam bahasa ini: fungsi main
, yang merupakan titik masuk dari banyak program. Anda juga sudah melihat kata kunci fn
, yang memungkinkan Anda mendeklarasikan fungsi baru.
Kode Cairo menggunakan snake case sebagai gaya konvensional untuk nama fungsi dan variabel, di mana semua huruf ditulis dalam huruf kecil dan garis bawah memisahkan kata-kata. Berikut adalah program yang berisi contoh definisi fungsi:
fn another_function() {
println!("Another function.");
}
fn main() {
println!("Hello, world!");
another_function();
}
Kita mendefinisikan fungsi di Cairo dengan menuliskan fn
diikuti oleh nama fungsi dan seperangkat tanda kurung. Kurung kurawal memberitahu kompiler di mana tubuh fungsi dimulai dan diakhiri.
Kita dapat memanggil setiap fungsi yang telah kita definisikan dengan menuliskan namanya diikuti oleh seperangkat tanda kurung. Karena another_function
didefinisikan dalam program, itu dapat dipanggil dari dalam fungsi main
. Perhatikan bahwa kita mendefinisikan another_function
sebelum fungsi main
dalam kode sumber; kita juga bisa mendefinisikannya setelahnya. Cairo tidak mempermasalahkan di mana Anda mendefinisikan fungsi Anda, yang penting adalah bahwa mereka didefinisikan di suatu tempat dalam cakupan yang dapat terlihat oleh pemanggil.
Mari kita mulai proyek baru dengan Scarb yang diberi nama functions untuk menjelajahi fungsi lebih lanjut. Tempatkan contoh another_function
di src/lib.cairo dan jalankannya. Anda seharusnya melihat output berikut:
$ scarb cairo-run
Compiling no_listing_15_functions v0.1.0 (listings/ch02-common-programming-concepts/no_listing_15_functions/Scarb.toml)
Finished `dev` profile target(s) in 4 seconds
Running no_listing_15_functions
Hello, world!
Another function.
Run completed successfully, returning []
The lines execute in the order in which they appear in the main
function. First the Hello, world!
message prints, and then another_function
is called and its message is printed.
Parameter
Kita dapat mendefinisikan fungsi dengan parameter, yang merupakan variabel khusus yang merupakan bagian dari tanda tangan fungsi. Ketika sebuah fungsi memiliki parameter, Anda dapat memberikannya nilai konkret untuk parameter-parameter tersebut. Secara teknis, nilai konkret disebut argument, tetapi dalam percakapan sehari-hari, orang cenderung menggunakan kata parameter dan argument secara bergantian baik untuk variabel dalam definisi fungsi atau nilai konkret yang dilewatkan saat Anda memanggil fungsi.
Pada versi another_function
ini, kita menambahkan sebuah parameter:
fn main() {
another_function(5);
}
fn another_function(x: felt252) {
println!("The value of x is: {}", x);
}
Coba jalankan program ini; Anda seharusnya mendapatkan output berikut:
$ scarb cairo-run
Compiling no_listing_16_single_param v0.1.0 (listings/ch02-common-programming-concepts/no_listing_16_single_param/Scarb.toml)
Finished `dev` profile target(s) in 4 seconds
Running no_listing_16_single_param
The value of x is: 5
Run completed successfully, returning []
The declaration of another_function
has one parameter named x
. The type of x
is specified as felt252
. When we pass 5
in to another_function
, the println!
macro puts 5
where the pair of curly brackets containing x
was in the format string.
Dalam fungsi signature, Anda harus mendeklarasikan tipe setiap parameter. Ini adalah keputusan yang disengaja dalam desain Cairo: memerlukan anotasi tipe dalam definisi fungsi berarti hampir tidak pernah compiler memerlukan Anda untuk menggunakannya di tempat lain dalam kode untuk mengetahui jenis data apa yang Anda maksud. Compiler juga dapat memberikan pesan kesalahan yang lebih membantu jika mengetahui tipe data yang diharapkan oleh fungsi.
Ketika mendefinisikan beberapa parameter, pisahkan deklarasi parameter dengan koma, seperti ini:
fn main() {
print_labeled_measurement(5, "h");
}
fn print_labeled_measurement(value: u128, unit_label: ByteArray) {
println!("The measurement is: {value}{unit_label}");
}
This example creates a function named print_labeled_measurement
with two parameters. The first parameter is named value
and is a u128
. The second is named unit_label
and is of type ByteArray
- Cairo's internal type to represent string literals. The function then prints text containing both the value
and the unit_label
.
Mari coba menjalankan kode ini. Gantilah program yang saat ini ada dalam file src/lib.cairo proyek functions Anda dengan contoh sebelumnya dan jalankannya menggunakan scarb cairo-run
:
$ scarb cairo-run
Compiling no_listing_17_multiple_params v0.1.0 (listings/ch02-common-programming-concepts/no_listing_17_multiple_params/Scarb.toml)
Finished `dev` profile target(s) in 5 seconds
Running no_listing_17_multiple_params
The measurement is: 5h
Run completed successfully, returning []
Because we called the function with 5
as the value for value and "h"
as the value for unit_label
, the program output contains those values.
Named Parameters
Di Cairo, parameter dengan nama memungkinkan Anda menentukan nama argumen saat Anda memanggil suatu fungsi. Hal ini membuat pemanggilan fungsi lebih mudah dibaca dan lebih deskriptif. Jika Anda ingin menggunakan parameter dengan nama, Anda perlu menentukan nama parameter dan nilai yang ingin Anda lewatkan kepadanya. Syntaxnya adalah nama_parameter: nilai
. Jika Anda melewatkan variabel yang memiliki nama yang sama dengan parameter, Anda dapat hanya menulis :nama_parameter
alih-alih nama_parameter: nama_variabel
.
Berikut adalah contohnya:
fn foo(x: u8, y: u8) {}
fn main() {
let first_arg = 3;
let second_arg = 4;
foo(x: first_arg, y: second_arg);
let x = 1;
let y = 2;
foo(:x, :y)
}
Pernyataan dan Ekspresi
Badan fungsi terdiri dari serangkaian pernyataan yang opsionalnya diakhiri dengan sebuah ekspresi. Sejauh ini, fungsi-fungsi yang telah kita bahas belum mencakup ekspresi di akhirnya, tetapi Anda telah melihat ekspresi sebagai bagian dari pernyataan. Karena Cairo adalah bahasa berbasis ekspresi, ini adalah perbedaan penting yang perlu dipahami. Bahasa lain tidak memiliki perbedaan yang sama, jadi mari kita lihat apa itu pernyataan dan ekspresi serta bagaimana perbedaan mereka memengaruhi badan fungsi.
- Pernyataan adalah instruksi yang melakukan suatu tindakan dan tidak mengembalikan nilai.
- Ekspresi mengevaluasi menjadi nilai hasil. Mari kita lihat beberapa contoh.
Sebenarnya, kita sudah menggunakan pernyataan dan ekspresi. Membuat variabel dan memberikan nilai kepadanya dengan kata kunci let
adalah sebuah pernyataan. Pada Listing 2-1, let y = 6;
adalah sebuah pernyataan.
fn main() {
let y = 6;
}
Listing 2-1: A main
function declaration containing one statement
Definisi fungsi juga termasuk pernyataan; seluruh contoh sebelumnya adalah sebuah pernyataan itu sendiri.
Pernyataan tidak mengembalikan nilai. Oleh karena itu, Anda tidak dapat memberikan nilai dari suatu pernyataan let
ke variabel lain, seperti yang dicoba oleh kode berikut; Anda akan mendapatkan kesalahan:
fn main() {
let x = (let y = 6);
}
Ketika Anda menjalankan program ini, kesalahan yang akan Anda dapatkan akan terlihat seperti ini:
$ scarb cairo-run
Compiling no_listing_18_statements_dont_return_values v0.1.0 (listings/ch02-common-programming-concepts/no_listing_20_statements_dont_return_values/Scarb.toml)
error: Missing token TerminalRParen.
--> listings/ch02-common-programming-concepts/no_listing_20_statements_dont_return_values/src/lib.cairo:3:14
let x = (let y = 6);
^
error: Missing token TerminalSemicolon.
--> listings/ch02-common-programming-concepts/no_listing_20_statements_dont_return_values/src/lib.cairo:3:14
let x = (let y = 6);
^
error: Missing token TerminalSemicolon.
--> listings/ch02-common-programming-concepts/no_listing_20_statements_dont_return_values/src/lib.cairo:3:23
let x = (let y = 6);
^
error: Skipped tokens. Expected: statement.
--> listings/ch02-common-programming-concepts/no_listing_20_statements_dont_return_values/src/lib.cairo:3:23
let x = (let y = 6);
^^
warn[E0001]: Unused variable. Consider ignoring by prefixing with `_`.
--> listings/ch02-common-programming-concepts/no_listing_20_statements_dont_return_values/src/lib.cairo:3:9
let x = (let y = 6);
^
warn[E0001]: Unused variable. Consider ignoring by prefixing with `_`.
--> listings/ch02-common-programming-concepts/no_listing_20_statements_dont_return_values/src/lib.cairo:3:18
let x = (let y = 6);
^
error: could not compile `no_listing_18_statements_dont_return_values` due to previous error
error: `scarb metadata` exited with error
Pernyataan let y = 6
tidak mengembalikan nilai, sehingga tidak ada nilai yang dapat diikat oleh x
. Ini berbeda dari apa yang terjadi di bahasa lain, seperti C dan Ruby, di mana hasil dari assignment adalah nilai dari assignment tersebut. Dalam bahasa-bahasa tersebut, Anda dapat menulis x = y = 6
dan memiliki kedua x
dan y
bernilai 6
; hal ini tidak terjadi dalam Cairo.
Expressions evaluate to a value and make up most of the rest of the code that you’ll write in Cairo. Consider a math operation, such as 5 + 6
, which is an expression that evaluates to the value 11
. Expressions can be part of statements: in Listing 2-1, the 6
in the statement let y = 6;
is an expression that evaluates to the value 6
.
Calling a function is an expression since it always evaluates to a value: the function's explicit return value, if specified, or the 'unit' type ()
otherwise.
A new scope block created with curly brackets is an expression, for example:
fn main() {
let y = {
let x = 3;
x + 1
};
println!("The value of y is: {}", y);
}
Expression ini:
let y = {
let x = 3;
x + 1
};
adalah blok yang, dalam hal ini, mengevaluasi menjadi 4
. Nilai itu diikat ke y
sebagai bagian dari pernyataan let
. Perhatikan bahwa baris x + 1
tidak memiliki titik koma di akhir, yang berbeda dari sebagian besar baris yang telah Anda lihat sejauh ini. Ekspresi tidak memasukkan titik koma di akhir. Jika Anda menambahkan titik koma di akhir ekspresi, Anda mengubahnya menjadi pernyataan, dan kemudian tidak akan mengembalikan nilai. Ingatlah ini saat Anda menjelajahi nilai kembalian fungsi dan ekspresi selanjutnya.
Fungsi dengan Return Value
Fungsi dapat mengembalikan nilai kepada kode yang memanggilnya. Kita tidak memberi nama pada nilai-nilai kembalian, tetapi kita harus mendeklarasikan tipe mereka setelah panah (->
). Di Cairo, nilai kembalian fungsi bersinonim dengan nilai dari ekspresi terakhir dalam blok tubuh fungsi. Anda dapat mengembalikan nilai sebelumnya dari sebuah fungsi dengan menggunakan kata kunci return
dan menentukan sebuah nilai, tetapi sebagian besar fungsi mengembalikan ekspresi terakhir secara implisit. Berikut adalah contoh fungsi yang mengembalikan nilai:
fn five() -> u32 {
5
}
fn main() {
let x = five();
println!("The value of x is: {}", x);
}
Tidak ada panggilan fungsi, atau bahkan pernyataan let
dalam fungsi five
— hanya angka 5
itu sendiri. Itu adalah fungsi yang sepenuhnya valid dalam bahasa Cairo. Perhatikan bahwa tipe pengembalian fungsi juga ditentukan, yaitu -> u32
. Cobalah menjalankan kode ini; keluarannya seharusnya terlihat seperti ini:
$ scarb cairo-run
Compiling no_listing_20_function_return_values v0.1.0 (listings/ch02-common-programming-concepts/no_listing_22_function_return_values/Scarb.toml)
Finished `dev` profile target(s) in 4 seconds
Running no_listing_20_function_return_values
The value of x is: 5
Run completed successfully, returning []
Angka 5
dalam five
adalah nilai kembalian fungsi, itulah mengapa tipe pengembalian adalah u32
. Mari kita periksa ini lebih detail. Ada dua bagian penting: pertama, baris let x = five();
menunjukkan bahwa kita menggunakan nilai kembalian suatu fungsi untuk menginisialisasi variabel. Karena fungsi five
mengembalikan 5
, baris tersebut sama dengan yang berikut:
let x = 5;
Kedua, fungsi five
tidak memiliki parameter dan menentukan tipe nilai kembalian, tetapi tubuh fungsi tersebut hanya berisi angka 5
tanpa titik koma karena itu adalah suatu ekspresi yang nilainya ingin kita kembalikan. Mari kita lihat contoh lain:
fn main() {
let x = plus_one(5);
println!("The value of x is: {}", x);
}
fn plus_one(x: u32) -> u32 {
x + 1
}
Running this code will print x = 6
. But if we place a semicolon at the end of the line containing x + 1
, changing it from an expression to a statement, we’ll get an error:
fn main() {
let x = plus_one(5);
println!("The value of x is: {}", x);
}
fn plus_one(x: u32) -> u32 {
x + 1;
}
$ scarb cairo-run
Compiling no_listing_22_function_return_invalid v0.1.0 (listings/ch02-common-programming-concepts/no_listing_24_function_return_invalid/Scarb.toml)
error: Unexpected return type. Expected: "core::integer::u32", found: "()".
--> listings/ch02-common-programming-concepts/no_listing_24_function_return_invalid/src/lib.cairo:9:28
fn plus_one(x: u32) -> u32 {
^
error: could not compile `no_listing_22_function_return_invalid` due to previous error
error: `scarb metadata` exited with error
Pesan kesalahan utama, Unexpected return type
, mengungkapkan masalah inti dengan kode ini. Definisi fungsi plus_one
menyatakan bahwa itu akan mengembalikan u32
, tetapi pernyataan tidak dievaluasi menjadi suatu nilai, yang diwakili oleh ()
, yaitu tipe unit. Oleh karena itu, tidak ada yang dikembalikan, yang bertentangan dengan definisi fungsi dan menyebabkan kesalahan.