Structları Tanımlama ve Örnekleme

Struct'lar, Veri Tipleri bölümünde tartışılan tuple'lar gibi, birden fazla ilgili değeri tutar. Tuple'lar gibi, bir struct'ın parçaları farklı tiplerde olabilir. Tuple'lar ile farklı olarak, bir struct'ta her bir veri parçasını adlandırırsınız, böylece değerlerin ne anlama geldiği açıktır. Bu adları eklemek, struct'ları tuple'lardan daha esnek hale getirir: bir örneğin değerlerini belirtmek veya erişmek için veri sırasına bağımlı olmanıza gerek yoktur.

Bir struct tanımlamak için, struct anahtar kelimesini girer ve tüm struct'ı adlandırırız. Bir struct'ın adı, bir araya getirilen veri parçalarının önemini açıklamalıdır. Sonra, süslü parantezler içinde, alanları adlandırırız ve veri parçalarının adlarını ve tiplerini tanımlarız. Örneğin, Liste 5-1 bir kullanıcı hesabı hakkında bilgi depolayan bir struct'ı gösterir.

Filename: src/lib.cairo

#[derive(Drop)]
struct User {
    active: bool,
    username: ByteArray,
    email: ByteArray,
    sign_in_count: u64,
}

Listing 5-1: A User struct definition

Bir struct'ı tanımladıktan sonra kullanmak için, her bir alan için somut değerler belirterek o struct'ın bir örneğini oluştururuz. Bir örneği oluşturmak için, struct'ın adını belirtir ve sonra anahtar: değer çiftleri içeren süslü parantezler ekleriz, burada anahtarlar alanların adlarıdır ve değerler, bu alanlarda saklamak istediğimiz verilerdir. Struct'ta tanımladığımız sırayla aynı sırada alanları belirtmek zorunda değiliz. Diğer bir deyişle, struct tanımı, tip için genel bir şablon gibidir ve örnekler, belirli verilerle o şablonu doldurarak tipin değerlerini oluşturur.

For example, we can declare two particular users as shown in Listing 5-2.

Filename: src/lib.cairo

#[derive(Drop)]
struct User {
    active: bool,
    username: ByteArray,
    email: ByteArray,
    sign_in_count: u64,
}

fn main() {
    let user1 = User {
        active: true, username: "someusername123", email: "someone@example.com", sign_in_count: 1,
    };
    let user2 = User {
        sign_in_count: 1, username: "someusername123", active: true, email: "someone@example.com",
    };
}

Listing 5-2: Creating two instances of the User struct

To get a specific value from a struct, we use dot notation. For example, to access user1's email address, we use user1.email. If the instance is mutable, we can change a value by using the dot notation and assigning into a particular field. Listing 5-3 shows how to change the value in the email field of a mutable User instance.

Filename: src/lib.cairo

#[derive(Drop)]
struct User {
    active: bool,
    username: ByteArray,
    email: ByteArray,
    sign_in_count: u64,
}
fn main() {
    let mut user1 = User {
        active: true, username: "someusername123", email: "someone@example.com", sign_in_count: 1,
    };
    user1.email = "anotheremail@example.com";
}

fn build_user(email: ByteArray, username: ByteArray) -> User {
    User { active: true, username: username, email: email, sign_in_count: 1 }
}

fn build_user_short(email: ByteArray, username: ByteArray) -> User {
    User { active: true, username, email, sign_in_count: 1 }
}


Listing 5-3: Changing the value in the email field of a User instance

Tüm örneğin değiştirilebilir olması gerektiğini unutmayın; Cairo, belirli alanların değiştirilebilir olarak işaretlenmesine izin vermez.

Herhangi bir ifade gibi, fonksiyon gövdesinin son ifadesi olarak struct'ın yeni bir örneğini oluşturarak bu yeni örneği dolaylı olarak döndürebiliriz.

Liste 5-4, verilen e-posta ve kullanıcı adı ile bir User örneği döndüren bir build_user fonksiyonunu gösterir. active alanı true değerini alır ve sign_in_count alanı 1 değerini alır.

Filename: src/lib.cairo

#[derive(Drop)]
struct User {
    active: bool,
    username: ByteArray,
    email: ByteArray,
    sign_in_count: u64,
}
fn main() {
    let mut user1 = User {
        active: true, username: "someusername123", email: "someone@example.com", sign_in_count: 1,
    };
    user1.email = "anotheremail@example.com";
}

fn build_user(email: ByteArray, username: ByteArray) -> User {
    User { active: true, username: username, email: email, sign_in_count: 1 }
}

fn build_user_short(email: ByteArray, username: ByteArray) -> User {
    User { active: true, username, email, sign_in_count: 1 }
}


Listing 5-4: A build_user function that takes an email and username and returns a User instance.

Fonksiyon parametrelerinin adını struct alanları ile aynı adlandırmak mantıklıdır, ancak email ve username alan adlarını ve değişkenleri tekrar etmek biraz yorucudur. Struct daha fazla alana sahip olsaydı, her adı tekrar etmek daha da can sıkıcı olurdu. Neyse ki, kullanışlı bir kısayol var!

Alan Başlatma Kısayolu Kullanımı

Liste 5-4'te parametre adları ile struct alan adları tam olarak aynı olduğu için, build_user'ı tam olarak aynı davranışı göstermek üzere yeniden yazmak için alan başlatma kısayol sözdizimini kullanabiliriz, böylece username ve email tekrarını ortadan kaldırabiliriz, Liste 5-5'te gösterildiği gibi.

Filename: src/lib.cairo

#[derive(Drop)]
struct User {
    active: bool,
    username: ByteArray,
    email: ByteArray,
    sign_in_count: u64,
}
fn main() {
    let mut user1 = User {
        active: true, username: "someusername123", email: "someone@example.com", sign_in_count: 1,
    };
    user1.email = "anotheremail@example.com";
}

fn build_user(email: ByteArray, username: ByteArray) -> User {
    User { active: true, username: username, email: email, sign_in_count: 1 }
}

fn build_user_short(email: ByteArray, username: ByteArray) -> User {
    User { active: true, username, email, sign_in_count: 1 }
}


Listing 5-5: A build_user function that uses field init shorthand because the username and email parameters have the same name as struct fields.

Burada, email adında bir alanı olan User struct'ının yeni bir örneğini oluşturuyoruz. email alanının değerini build_user fonksiyonunun email parametresindeki değere ayarlamak istiyoruz. email alanı ve email parametresi aynı adı taşıdığı için, email: email yerine yalnızca email yazmamız yeterlidir.

Creating Instances from Other Instances with Struct Update Syntax

It’s often useful to create a new instance of a struct that includes most of the values from another instance, but changes some. You can do this using struct update syntax.

First, in Listing 5-6 we show how to create a new User instance in user2 regularly, without the update syntax. We set a new value for email but otherwise use the same values from user1 that we created in Listing 5-2.

Filename: src/lib.cairo

#[derive(Drop)]
struct User {
    active: bool,
    username: ByteArray,
    email: ByteArray,
    sign_in_count: u64,
}

fn main() {
    // --snip--

    let user1 = User {
        email: "someone@example.com", username: "someusername123", active: true, sign_in_count: 1,
    };

    let user2 = User {
        active: user1.active,
        username: user1.username,
        email: "another@example.com",
        sign_in_count: user1.sign_in_count,
    };
}


Listing 5-6: Creating a new User instance using all but one of the values from user1

Using struct update syntax, we can achieve the same effect with less code, as shown in Listing 5-7. The syntax .. specifies that the remaining fields not explicitly set should have the same value as the fields in the given instance.

Filename: src/lib.cairo

use core::byte_array;
#[derive(Drop)]
struct User {
    active: bool,
    username: ByteArray,
    email: ByteArray,
    sign_in_count: u64,
}

fn main() {
    // --snip--

    let user1 = User {
        email: "someone@example.com", username: "someusername123", active: true, sign_in_count: 1,
    };

    let user2 = User { email: "another@example.com", ..user1 };
}


Listing 5-7: Using struct update syntax to set a new email value for a User instance but to use the rest of the values from user1

The code in Listing 5-7 also creates an instance of user2 that has a different value for email but has the same values for the username, active, and sign_in_count fields as user1. The ..user1 part must come last to specify that any remaining fields should get their values from the corresponding fields in user1, but we can choose to specify values for as many fields as we want in any order, regardless of the order of the fields in the struct’s definition.

Note that the struct update syntax uses = like an assignment; this is because it moves the data, just as we saw in the "Moving Values" section. In this example, we can no longer use user1 as a whole after creating user2 because the ByteArray in the username field of user1 was moved into user2. If we had given user2 new ByteArray values for both email and username, and thus only used the active and sign_in_count values from user1, then user1 would still be valid after creating user2. Both active and sign_in_count are types that implement the Copy trait, so the behavior we discussed in the "Copy Trait" section would apply.