30 września 2019

C# samouczek część IV, czyli znam już trochę zmienne i co mogę z nimi zrobić.



W poprzednim odcinku objaśniałem czym są zmienne i co można do nich wpakować. Czego nie wyjaśniałem, to jak z kolei z tych zmiennych korzystać. 


Aby zadeklarować jakąś zmienną musimy w kodzie podać jej typ, oraz nazwę (identyfikator). O ile typy już znamy, o tyle o nazwach jeszcze nic nie wspomniałem. Nazwa naszej zmiennej musi składać się z liter (ale tylko łacińskich, bo amerykanie, którzy opracowali ten język są nieufni wobec liter, których nie ma w ich alfabecie) i może zawierać cyfry, lub znaki “_” lub “@” (chociaż tego drugiego zdecydowanie nie polecam, a wyjaśnię szerzej, gdy dojdziemy do operacji na łańcuchach znaków). Nazwa nie może zaczynać się od cyfry. Generalnie zasady te odnoszą się do wszystkiego co można w C# sobie nazwać po swojemu i nie będę już do nich wracał. Gdybyśmy chcieli więc oznajmić naszemu programowi, że ma stworzyć 32 bitową zmienną całkowitoliczbową i nadać jej imię Zuzanna robimy to tak: 

int Zuzanna; 

Zadeklarowanej w ten sposób zmiennej nie powinniśmy odczytywać (poprawnie ustawiony kompilator zresztą, czy też środowisko programistyczne wskaże nam to jako błąd), ponieważ w tym momencie zawartość tej zmiennej może być dość przypadkowa, ponieważ tworząc zmienną po prostu rezerwujemy sobie na nią pamięć i tyle. Żeby móc więc ją odczytać, najpierw wypadałoby coś do niej zapisać. Aby zapisać coś naszej Zuzannie wystarczy posłużyć się operatorem “=” (operatorów jest trochę więcej, ale o tym jak zwykle - później). 

Zuzanna = 22; 

Zuzanna ma więc wartość 22. Ale to są dwie linijki kodu, a programiści są znani z tego, że aby zaoszczędzić kilka minut czasu są zdolni poświęcić nawet kilka godzin, dlatego wpadli na to, że właściwie wszystko (a więc deklaracje i przypisanie wartości) można zrobić za jednym zamachem. 

int Zuzanna = 22; 

Okazuje się, że z tym lenistwem i oszczędzaniem linijek kodu można pójść nawet dalej i zrobić tak: 

int Zuzanna = 22, Adrian = 23; 

Tak moi drodzy, można nie tylko zadeklarować dwie zmienne na raz, ale też i od razu je zainicjalizować (czyli przypisać im jakąś wartość początkową). Mamy więc już aż dwie zmienne, czy można coś z nimi zrobić? W końcu komputer to po angielsku “maszyna licząca” tak więc możemy coś sobie policzyć na tych zmiennych. Możemy dodeklarować trzecią zmienną “wynik”. 

int wynik; 

I tenże wynik może być np. różnicą wartości Zuzanny i Adriana. 

wynik = Adrian - Zuzanna; 

W tej chwili wynik odejmowania Zuzanny od Adriana, albo wynik odejmowania wartości ukrytych pod tymi identyfikatorami zostaje zapisany do zmiennej “wynik”. Aż się prosi o to, aby sobie trochę rzecz uprościć i za jednym zamachem zadeklarować zmienną i zapisać jej wartość. 

int wynik = Adrian - Zuzanna; 

Nasuwa się więc pytanie, skoro takie jednolinijkowce przechodzą tak bezboleśnie, to czy można w jednej linijce zadeklarować dwie zmienne, zainicjalizować je i wykorzystać do inicjalizacji kolejnej? Otóż nie. Programiści odpowiedzialni za język C# (albo raczej jego architekci) jeszcze nie doszli do tego, że komuś mogłoby to ułatwić życie. Ja osobiście wolę w jednej linijce deklarować i inicjalizować tylko jedną zmienną, bo w razie co łatwiej jest ją wyrzucić. 

Ok. Wiemy już jak deklarujemy zmienne, a czy wiemy gdzie w kodzie można to zrobić? Odpowiedź brzmi prawie wszędzie, ale dokładne miejsce zależy od tego do czego nam ta zmienna będzie służyć i gdzie ma być dostępna. Co do zasady nasze zmienne powinny być niedostępne tam, gdzie nie są potrzebne. Posługując się więc naszym programem z rozdziału drugiego (lekko tylko zmodyfikowanym) postaram się wyjaśnić różnice. 

1  using System;                          
2  using System.Collections.Generic;      
3  using System.Text;                     
4                                         
5  namespace HelloWorld                   
6  {                                      
7                                         
8   class Program                         
9   {                                     
10                                        
11     static void Main(string[] args)    
12     {                                  
13                                        
14       Console.WriteLine("Hello World");
15     }                                  
16   }                                    
17 }                                      

Specjalnie zostawiłem kilka pustych linii aby łatwiej było sobie wyobrazić, że tam właśnie wylądują nasze deklaracje.

Linia 4 - tutaj nie możemy deklarować zmiennych. Nie i już. Możemy oczywiście próbować, ale kompilator się na nas obrazi i nie zechce podjąć współpracy. 

Linia 7 - zmienne umieszczone tutaj będa dostępne dla całej przestrzeni nazw “HelloWorld” (bo taka jest jej nazwa). Przestrzeń nazw pozwala nam połączyć ze sobą w logiczną całość kilka klas, aby było łatwiej się do nich odwoływać. Na tak małym przykładzie trudno jest niestety dostrzec sensowność takiego rozwiązania, ale przydaje się to np. gdy łączymy kilka małych projektów w jedną dużą całość - wtedy nawet gdyby te projekty używały tych samych zmiennych to dzięki poupychaniu ich w różne przestrzenie nazw nie będziemy mieć żadnych konfliktów (choć bardziej niż zmiennych dotyczy to nazw klas). 

Linia 10 - zmienna umieszczona tutaj będzie dostępna dla wszystkich elementów danej klasy (a właściwie instancji tej klasy - ale o tym jak zwykle - później) bez ograniczeń. Pozostałe obiekty mogą używać tych zmiennych tylko gdy są one oznaczone jako publiczne za pomocą słowa kluczowego public przed deklaracją typu, natomiast elementy wewnątrz tej klasy będą mogły sobie używać tej zmiennej do woli. Generalnie nie jest zalecane bezpośrednie wystawianie zmiennych, ale o tym jak sobie z tym poradzić opowiemy sobie, gdy dojdziemy do programowania obiektowego. 

Linia 13 - zmienna zadeklarowana tutaj będzie dostępna tylko wewnątrz funkcji (prawidłowa nazwa, to “metoda”, ale ja po prostu pierwsze kroki w programowaniu stawiałem w Turbo Pascalu i tam było takie fajne rozgraniczenie, że to co nie zwraca wyniku, to procedura, a to co zwraca - to funkcja, potem w C wszystko już było funkcją i jakoś w nazewnictwie na tym się zatrzymałem, bo ludzie już nie wiedzą co to jest procedura, ale jeszcze pamiętają czym jest funkcja, więc generalnie wiedzą o co mi chodzi) w której została zadeklarowana i choćby się skały zesrały nic już z tym nie można zrobić, chyba, że zwrócimy ją jako wynik funkcji. Zgadliście - o tym też będzie później. O czym trzeba pamiętać, że po zakończeniu wykonywania się funkcji zawartość zmiennych jest nie do odzyskania. Każde nowe odpalenie funkcji zaczyna “na świeżo” (program może zwolnić pamięć przydzieloną dla tych zmiennych, co też prędzej czy później się dzieje). 

Dowolny (no prawie dowolny) blok kodu zamknięty nawiasami klamrowymi wewnątrz funkcji - zmienna będzie dostępna tylko w tym bloku kodu, a po jego opuszczeniu zostanie “zapomniana”, a przydzielona jej pamięć będzie prędzej, czy później zwolniona. W przypadku operowania na zmiennych, które zajmują dużo pamięci można posiłkować się deklaracją takiej zmiennej z użyciem słowa kluczowego using, co pozwala na zwolnienie pamięci natychmiast, gdy nie jest już potrzebna. Taki blok kodu możemy zastosować tylko wewnątrz funkcji i wyglądać on może np. tak: 

using (JakasBardzoDuzaKlasa jakisBardzoDuzyObiekt = new JakasBardzoDuzaKlasa()
{
  jakisBardzoDuzyObiekt.JakisSkomplikowanyKodDoWykonania();
}

Na koniec - dobra rada. Wymyślając nazwy dla swoich zmiennych człowiek dość szybko ulega pokusie, aby zastąpić je pojedynczymi literami - bo przecież działa, ale generalnie nie polecam, no może poza sytuacjami, gdy zmienna naprawdę potrzebna jest tylko “na chwilkę”. Na co dzień jednak lepiej, aby nazwa zmiennej odzwierciedlała do czego też owa zmienna ma służyć. W przykładzie powyżej zastosowałem dwie metody nazewnictwa zalecane przez autorów C#. PascalCase stosujemy do elementów dostępnych publicznie i polega na nazywaniu tych elementów zgodnie z ich funkcją zaczynając od wielkiej litery i tak, jeśli mamy gdzieś publiczną funkcję która policzy nam wiek Zuzanny powinniśmy ją nazwać np. ObliczWiekZuzanny. Z kolei do elementów prywatnych, a więc dostępnych tylko dla klasy w której się akurat szarogęsimy zalecany jest tzw. camelCase. Różni się tylko tym, że pierwsze litera jest literą małą - w związku z tym, gdyby nasza funkcja była metodą prywatną powinna się nazywać obliczWiekZuzanny. Gdyby jednak, jakimś cudem zdarzyło się Wam zdryfować w kierunku języków w których nie mamy jako takich typów zmiennych, albo mamy tzw. typowanie słabe (nie wprost), wtedy nieoceniona jest tzw. notacja węgierska, czyli camelCase lub PascalCase poprzedzone pierwszą literką typu - czyli gdyby nasza metoda zwracała wartość całkowitoliczbową nazywałaby się iObliczWiekZuzanny.

W następnym odcinku - operatory matematyczne i logiczne.
W poprzednim odcinku - typy zmiennych.


P.S. Haifisch - cover lepszy od oryginału.

Brak komentarzy:

Prześlij komentarz

„Obrażać też trzeba umieć!”

W zasadzie ten jeden cytat wystarczyłby za cały wpis. Nie wiem, czy w tym ukopanym kraju uchował się jeszcze ktokolwiek powyżej 25 roku życi...