Dlaczego musisz podać typ danych podczas deklarowania zmiennych?

41

W większości języków kodowania (jeśli nie wszystkie) należy zadeklarować zmienne. Na przykład w C #, jeśli to pole liczbowe, to

int PhoneNumber

Jeśli używam normalnego języka angielskiego, nie muszę deklarować, PhoneNumberże intgo używam. Na przykład, jeśli poproszę mojego przyjaciela Sama o podanie mi jego numeru telefonu, mówię:

„Sam daj mi numer telefonu”

Nie powiedziałbym

„Char (20) Sam daj mi numer telefonu wewnętrznego”

Dlaczego w ogóle musimy określać typ danych?

Dick Smith
źródło
83
To dlatego, że angielski ma niejawne pisanie - więc twój numer telefonu jest domyślnie wpisany jako numer telefonu - ludzie mają również dynamiczny przydział pamięci ...;)
HorusKol
28
Ty i Sam wiesz, że numer telefonu składa się z cyfr i zdziwiłbyś się, gdyby znalazł w nim literę. Komputery nie muszą i muszą zostać poinformowane.
Thorbjørn Ravn Andersen
16
A kiedy słyszę jak numery 1-800-Jimbo w filmach, moja myśl: Jak to jest numer ? Oo
muru
103
Nie należy deklarować numeru telefonu jako int. W większości języków programowania spowoduje to usunięcie zer wiodących.
Aron_dc
25
@HorusKol: ludzie mają nie tylko dynamiczną alokację pamięci, ale także wysoce niekonserwatywny
moduł wyrzucający

Odpowiedzi:

79

W większości języków kodowania (jeśli nie wszystkie) należy zadeklarować zmienne.

[…]

Dlaczego w ogóle musimy określać typ danych?

To są dwa niezależne pytania:

  • Dlaczego musimy deklarować zmienne?
  • Dlaczego musimy deklarować typy?

Nawiasem mówiąc, odpowiedź na oba pytania brzmi: my nie.

Istnieje wiele statycznie wpisywanych języków programowania, w których nie trzeba deklarować typów. Kompilator może wywnioskować typy z otaczającego kontekstu i użycia.

Na przykład w Scali można powiedzieć

val age: Int = 23

lub możesz po prostu powiedzieć

val age = 23

Oba są dokładnie równoważne: kompilator wywnioskuje typ Intz wyrażenia inicjującego 23.

Podobnie w języku C♯ możesz powiedzieć jedno z nich i oba oznaczają dokładnie to samo:

int age = 23;
var age = 23;

Ta funkcja nosi nazwę wnioskowania typu i ma ją wiele języków poza Scalą i C♯: Haskell, Kotlin, Ceylon, ML, F♯, C ++. Nawet Java ma ograniczone formy wnioskowania typu.

W dynamicznie wpisywanych językach programowania zmienne nawet nie mają typów. Typy istnieją tylko dynamicznie w czasie wykonywania, a nie statycznie. Tylko wartości i wyrażenia mają typy, a tylko w czasie wykonywania zmienne nie mają typów.

Np. W ECMAScript:

const age = 23;
let age = 23;

I wreszcie, w wielu językach, nie musisz nawet deklarować zmiennych. np. w Ruby:

age = 23

W rzeczywistości ten ostatni przykład obowiązuje w wielu językach programowania. Dokładnie taki sam wiersz kodu działałby również na przykład w Pythonie.

Więc,

  • nawet w językach o typie statycznym, w których zmienne mają typy, niekoniecznie musisz je deklarować,
  • w dynamicznie wpisywanych językach zmienne nie mają typów, więc oczywiście nie można ich nawet zadeklarować,
  • w wielu językach nie musisz nawet deklarować zmiennych
Jörg W Mittag
źródło
2
Plus jeden za wyjaśnienie zarówno wnioskowania typu, jak i dynamicznego pisania (późne wiązanie)
dcorking
36
To świetna informacja na temat nieporozumień stojących za pytaniem, ale wciąż pozostawia pytanie bez odpowiedzi. Pytanie bardziej poprawnie brzmi: dlaczego musimy określić typ danych, kiedy deklarujemy zmienne w językach, które tego wymagają? Dlaczego zostały tak zaprojektowane? Odpowiedzi na to pytanie są dobre i chociaż opracowywanie alternatywnych rozwiązań poszerza horyzonty PO i jest bardzo dobre, nie wydaje mi się to kompletne.
KRyan
7
@ KR Ryan: jeśli chcesz wiedzieć, dlaczego pewien projektant języka wybrał konkretny projekt językowy, obawiam się, że musisz go zapytać. Nie mogę ci powiedzieć, dlaczego projektanci C♯ zdecydowali się nie wnioskować o typie, ani nie mogę ci powiedzieć, dlaczego później zmienili zdanie. Projektowanie języka jest mocno opiniotwórcze i często sprowadza się do smaku. Jeśli, OTOH, chcesz wiedzieć o konkretnych kompromisach, odpowiedzią byłby w zasadzie ponowny wydruk rodzajów i języków programowania prof. Pierce'a, który jest o wiele za szeroki dla stosu wymiany.
Jörg W Mittag
2
JörgWMittag: jak już powiedział @KRyan, odpowiedź „nie musisz” nie jest bardzo interesująca (jest banalnie oczywista - wiele języków pozwala w niektórych przypadkach pomijać deklaracje typu). Pytanie „dlaczego chcesz zadeklarować typy” jest o wiele bardziej interesujące i lepiej odzwierciedla ducha pierwotnego pytania (twoja odpowiedź przypomina mi żart: „gdzie jesteśmy?” - „jesteś w balonie na ogrzane powietrze” ! ” ). Nie musisz wiedzieć, co myślał wówczas projektant określonego języka, aby podać kilka dobrych powodów na rzecz deklaracji typu.
jfs
1
@Zaibis: auto i = 1 // i is inferred to type int, vector<int> vec; auto itr = vec.iterator(); // itr is inferred to type vector<int>::iteratori tak dalej. Jeśli chcesz wiedzieć, jak to dokładnie działa, możesz to sprawdzić w specyfikacji.
Jörg W Mittag
53

Kiedy używasz języka naturalnego do odnoszenia się do informacji, nie jest to bardzo precyzyjne, a w szczególności nie przekazuje innym informacji o twoich zamiarach. Podobne problemy występują podczas próby wykonywania matematyki w języku naturalnym: po prostu nie jest wystarczająco precyzyjna.

Programowanie jest złożone; błędy są zbyt łatwe do znalezienia. Typy są częścią systemu kontroli zaprojektowanego w celu zapobiegania nielegalnym stanom programu poprzez wykrywanie warunków błędów. Różne języki używają typów w różny sposób: niektóre języki intensywnie używają typów do wykrywania błędów w czasie kompilacji. Prawie wszystkie języki mają pewne pojęcie niekompatybilnych typów jako błąd środowiska wykonawczego. Zwykle błąd typu wskazuje na jakiś błąd w programie. Gdy zezwalamy na kontynuowanie programów pomimo błędów, prawdopodobnie otrzymujemy bardzo złe odpowiedzi. Wolimy zatrzymać program niż otrzymywać złe lub niepoprawne odpowiedzi.

Innymi słowy, typy wyrażają ograniczenia w zachowaniu programu. Ograniczenia, gdy są egzekwowane przez jakiś mechanizm, dają gwarancje. Takie gwarancje ograniczają zakres rozumowania niezbędny do myślenia o programie, tym samym upraszczając zadanie czytania i utrzymywania programu dla programistów. Bez typów i ich implikacji narzędzi (tj. Kompilatora), które wykrywają błędy typu, obciążenie programistyczne jest znacznie wyższe, a zatem bardziej kosztowne.

Prawdą jest, że (wielu) ludzi łatwo rozróżnia europejski, amerykański i międzynarodowy numer telefonu. Jednak komputer tak naprawdę nie „myśli” i wybrałby numer telefonu Stanów Zjednoczonych w Europie lub odwrotnie. Na przykład typy są dobrym sposobem na rozróżnienie tych przypadków bez konieczności uczenia komputera, jak „myśleć”. W niektórych językach możemy otrzymać błąd czasu kompilacji podczas próby zmiksowania europejskiego numeru telefonu w amerykańskim systemie telefonicznym. Ten błąd mówi nam, że musimy zmodyfikować nasz program (być może poprzez konwersję numeru telefonu na międzynarodową sekwencję wybierania numerów lub, zamiast tego, używając numeru telefonu w Europie), zanim jeszcze spróbujemy uruchomić program.

Ponadto, ponieważ komputer nie myśli, nazwa pola lub zmiennej (np. phonenumber) Nic dla komputera nie znaczy. Dla komputera ta nazwa pola / zmiennej to po prostu „blah123”. Pomyśl, jak wyglądałby twój program, gdyby wszystkie zmienne były „blahxxx”. Yikes. Tak właśnie widzi komputer. Podanie typu daje komputerowi pojęcie o znaczeniu zmiennej, którego po prostu nie może wywnioskować z samej nazwy.

Ponadto, jak mówi @Robert, w wielu współczesnych językach nie musimy określać typów tak, jak robiliśmy to w dawnych czasach, ponieważ języki takie jak C # wykonują „wnioskowanie o typie”, czyli zbiór reguł określających właściwy typ dla zmiennej w kontekście. C # zapewnia wnioskowanie typu tylko na zmiennych lokalnych, ale nie na parametrach formalnych ani polach klasy lub instancji.

Erik Eidt
źródło
4
RE smutna część: Nie można wnioskować o typie publicznie dostępnego elementu (pole publiczne, podpis metody publicznej), ponieważ nie można przewidzieć, kiedy i jak zostanie użyty. Adnotacje typu są także dokumentacją.
Sergio Tulentsev
Myślę, że powinieneś wyróżnić / pogrubić ten wiersz: Types are part of a system of checks that ...ponieważ odpowiada on bezpośrednio PO Why do we have to specify data type at all?
txtechhelp
Uwaga: odpowiedź zakłada, że ​​język używany do określania typów jest w jakiś sposób lepszy w unikaniu błędów niż zwykły język programowania. Oczywiście nie jest tak, np. Weź pod uwagę język szablonów C ++, który jest kompletny Turinga (a zatem pozwala wyrazić wiele kontroli błędów), ale jest prawie nieczytelny w porównaniu do wielu innych języków kompletnych Turinga, takich jak Haskell, Python, a nawet inne części Sam C ++. Zadaj sobie pytanie, dlaczego nie użyjesz tego samego języka programowania, aby wyrazić kontrole błędów jak reszta programu (w niektórych, ale nie we wszystkich przypadkach istnieją dobre odpowiedzi).
jfs
@SergioTulentsev To nieprawda - w F # możesz mieć metody publiczne bez wyraźnego określania ich typów. Kompilator wywnioskuje typy na podstawie użycia wewnątrz metody. Na przykład następujące poprawne definicje metod publicznych: static member add x y = x + y, member x.Append s = x.Text + s. W pierwszym przypadku, xi ybędą wywodzić się intdlatego, dodawania. W drugim przypadku będą to, co jest poprawne, w zależności od typu x.Text- jeśli to string, to również sbędzie string. Zgadzam się jednak, że adnotacje typu są dokumentacją.
Roujo
„Domniemane typy lokalne, jawne typy interfejsów” to sposób, w jaki wiele osób programuje, nawet w takich językach, jak Haskell, które pozwalają ominąć (prawie) wszystkie typy, a jednocześnie kompilator wyznaje ścisłe typy. Istnieje wiele osób, które nie uważają za smutne, gdy język wymusza tę praktykę (podobnie jak C #).
Ben
29

Oprócz innych odpowiedzi, należy uwzględnić jedną rzecz. Pamiętaj, że komputery to tylko bity. Powiedz, że podaję bajty:

26 3A 00 FF

Co oznacza, że średni ? Jest przechowywany w ten sposób przez komputer, ale bez żadnej interpretacji, to tylko fragmenty . Mogą to być 4 znaki ascii. Może to być liczba całkowita. Mogą to być niektóre bajty w tablicy. Może być częścią obiektu. Może to być wskaźnik do miejsca buforowania tego wideo kota. Prawie wszystkie języki programowania od asemblera do góry potrzebują czegoś, aby wiedzieć, jak interpretować bity, aby mogły wykonywać sensowne obliczenia.

A ponieważ komputer nie zna znaczenia tych bitów, musisz to powiedzieć - albo wprost za pomocą adnotacji typu, albo pośrednio poprzez mechanizmy wnioskowania typu wspomniane w innych odpowiedziach.

Telastyn
źródło
10
To prawda, ale aby naprawdę zaskoczyć twój umysł, zdaj sobie sprawę, że komputer nigdy nie jest w stanie zrozumieć, co oznaczają te bity - nawet jeśli powiesz mu więcej adnotacji. Twoje wyjaśnienia zamieniają się w jeszcze więcej liczb szesnastkowych, aby „wyjaśnić” pierwsze liczby szesnastkowe. Znaczenie jest tworzone przez ludzi, aby wprowadzić intencję do elektroniki i zmusić ich do robienia tego, co zamierzamy. Teraz powiedz inżynierowi „dziękuję”. :)
Wildcard
1
Spędziłem wiele lat programując na komputerach mainframe. W przypadku PL / 1 ta odpowiedź ma wiele sensu. Dość regularnie korzystamy z pamięci opartej na wskaźniku ustawionym na adres innej zmiennej innego typu danych, aby uzyskać dostęp do bajtów w inny sposób. Na przykład PL / 1 nie obsługuje 1-bajtowego binarnego pola numerycznego, ale zmienilibyśmy 1-znakową zmienną pod adresem, abyśmy mogli przechowywać 6-bajtową tablicę przechowującą 6 jednobajtowych pól binarnych (w tym przypadku pozwalając nam zapisać 6 bajtów na adres - co było ważne, gdy przechowywanie było drogie).
Kickstart
1
Komputer jest w stanie zrozumieć wiele możliwości, ale nawet sprytne kompilatory potrzebują kontekstu, aby zrozumieć. To nie to samo, co 0 lub „0”. Lub ciąg „31 grudnia” zostanie zamówiony przed „1 maja” traktowany jako ciąg, ale nie będzie traktowany jak data. Lub weź 5/2. Jest to 2 jako wejście, ale 2,5 jako podwójne. Ponadto typ jest środkiem zabezpieczającym przed niechcianymi konwersjami. Problemem mogą być również wartości zerowe, NaN oraz zaokrąglanie lub przepełnienia. Silne i statycznie typowane języki mają pewne zalety. Na przykład kompilator pomaga wykryć problemy podczas refaktoryzacji.
Borjab
1
@ Borjab Czy miałeś na myśli „It is 2 as integer ”?
Richard Everett
1
@RichardEverett Z pewnością to był lapsus. Dzięki, ale spóźniony, aby go edytować.
Borjab,
23

Odpowiedź na pytanie, dlaczego komputery potrzebują tych informacji, ma związek z reprezentacją danych .

Nazwa „typu danych” odnosi się do reguł, które pomagają komputerowi przechowywać i pobierać informacje z jego stanu surowego zer i jedynek w pamięci komputera.

Na przykład twój zwykły 8-bitowy znak ASCII byłby przechowywany w pamięci komputera (RAM lub Dysk) jako 01000001(wielkie litery „A”, kod ASCII 65) lub 00001000(znak procentu) lub dowolne kombinacje zer i 1 w tych 8 bitach.

W innym przykładzie niektóre 8-bitowe liczby całkowite bez znaku mogą być przechowywane jako 00000101(liczba 5) lub 00001000(liczba 8)

Zauważ, że binarna reprezentacja 8 i znaku% może być taka sama, ale oznaczają one różne rzeczy, ponieważ ich typy są różne.

Nawet języki, które wnioskują o typie danych, mogą nie mieć reguły, że „wszystkie typy zmiennych muszą być zadeklarowane przez programistę”, mają reguły takie jak „jeśli twoja seria znaków jest ujęta w cudzysłów, jest to ciąg znaków” i wiele innych reguł dla każdego typu danych.

Więc nawet te potrzebują typów danych, aby zrozumieć, co oznaczają cyfry 0 i 1, więc mogą na przykład wykonać funkcję konkatenacji ciągu, jeśli spróbujesz „dodać” dwa znaki lub dodać liczbę całkowitą, jeśli spróbujesz dodać dwie liczby całkowite .

W swojej historii też, powiedzmy, że nie prosiłem Sama o numer telefonu, ale Sam daje kawałek papieru, który ma „1123581321” na niej napisane. Nie możesz mieć pewności, czy Sam jest fanem pierwszych ośmiu liczb Fibonacciego, czy jest to numer telefonu. Aby zgadnąć, musisz wziąć pod uwagę kontekst i dostępne wskazówki, takie jak być może poprosiłeś Sama o numer telefonu dzień temu lub notatkę z napisem „Zadzwoń do mnie” lub jeśli policzysz cyfry i znajdziesz pasuje do wzorców większości numerów telefonów. Dopiero wtedy będziesz wiedział, że jest to numer telefonu, pod który możesz zadzwonić, a nie kilka cyfr, które wybiłbyś do kalkulatora.

Zwróć uwagę, że te wskazówki, które doprowadziły cię do przypuszczenia, że ​​numer był numerem telefonu, są podobne do tego, w jaki sposób wskazówki prowadzą do języka komputera, który nie wymaga deklaracji w celu wywnioskowania typu wartości.

Peeyush Kushwaha
źródło
3
To najbliższa odpowiedź. Wszystko to ma związek z pamięcią. Podajesz typ, aby kompilator wiedział, ile pamięci aplikacja powinna zażądać w czasie wykonywania. Znajomość interpretacji bitów jest kwestią drugorzędną.
Greg Burghardt,
@GregBurghardt true. Dla zrozumienia bitów już obecnych, a także umieszczenia bitów na pierwszym miejscu po konwersji danych na binarne zgodnie z typem danych.
Peeyush Kushwaha,
10

W niektórych językach nie trzeba określać typu danych.

Języki, w których obsługiwane jest wnioskowanie o typie, zazwyczaj mogą dowiedzieć się, jaki typ danych ma zastosowanie. Na przykład,

var name = "Ali"

jest wewnętrznie wpisany jako ciąg, ponieważ wartość jest otoczona cudzysłowami.

Niektóre języki również nie wymagają deklarowania zmiennej; zmienna jest tworzona przy pierwszym użyciu. Uważa się jednak, że najlepszą praktyką jest szczegółowe deklarowanie zmiennych z wielu ważnych powodów; głównie dlatego, że robienie tego lepiej wyraża Twoją intencję.

Robert Harvey
źródło
5
Ten var name = "Ali"styl jest właściwie wspólny dla współczesnych języków o typie statycznym . W językach o typie statycznym typ jest ustalany podczas tworzenia, ale nadal można go określić za pomocą inicjatora. Definicja języka o typie dynamicznym polega na tym, że typy dołączają się do wartości, a nie do zmiennych. Przypisanie wartości do zmiennej ustawia zatem również typ zmiennych.
MSalters
@MSalters: Wprowadziłem niewielkie poprawki do brzmienia.
Robert Harvey,
5
Ironią tutaj jest to, że obejmuje C # z tą dokładną składnią.
Derek Elkins
1
@MSalters Przypisanie wartości do zmiennej ustawia zatem również typ zmiennych. Lub, że zmienna nie ma własnego typu, a interpreter będzie próbował zastosować dowolną operację do wartości zmiennej. Czy są jakieś dynamicznie wpisywane języki, w których kod taki jak poniżej (JavaScript) byłby niedozwolony, var x = 5; x = "";ponieważ pierwsza instrukcja powoduje xskojarzenie typu „Liczba” x? Rodzaj konfliktów z dynamicznym pisaniem . A jeśli nie, jaki wpływ ma typ powiązany ze zmienną, poza powiązaniem typu z wartością?
Zev Spitz
1
@ZevSpitz: Pierwszy rodzaj systemu nie jest wpisywany dynamicznie, ale w ogóle nie jest wpisywany. Twój przykład Javascript nie jest wpisywany dynamicznie, właśnie dlatego, że nie można zmienić typu Number. W języku dynamicznie wpisywanym x = "";zmienia typ x na ciąg znaków, nawet jeśli poprzednio była liczbą.
MSalters
9

Ponieważ tak określa projekt języka. Aby odpowiedzieć na twoje pytanie, musimy przyjrzeć się celom jawnego pisania w językach takich jak C # i C ++. (C # robi to, ponieważ robi to C ++, ponieważ robi to C, więc musimy spojrzeć na to, co było w tamtym czasie).

Po pierwsze, pisanie jawne i statyczne zapewnia rygorystyczne kodowanie - określenie zmiennej jako liczby całkowitej oznacza, że ​​kompilator i oprogramowanie powinny być zaskoczone i zgłaszać błąd podczas przypisywania znaku lub łańcucha do zmiennej. Pisanie dynamiczne może powodować ból głowy dla nieostrożnych (wystarczy spojrzeć na PHP lub podejście javascripts do prawdziwości takich rzeczy jak tablice i puste ciągi znaków).

Możesz mieć statyczne z niejawnym pisaniem - inicjowanie zmiennej jako ciąg oznacza, że ​​zmienna powinna być zawsze ciągiem, ale mam wrażenie, że może to powodować problemy dla ludzi czytających kod (zazwyczaj zakładam, że pisanie dynamiczne jest niejawne ).

Ponadto w niektórych językach można napisać coś takiego jak ten pseudokod, aby zainicjować klasę na podstawie ciągu znaków:

PhoneNumber phoneNumber = "(61) 8 8000 8123";

Po drugie, wyraźne pisanie idzie w parze z alokacją pamięci. Liczba całkowita to zawsze tyle bajtów. Numer telefonu to tyle bajtów. Kompilator może przypisać blok pamięci o odpowiednim rozmiarze, który może być później wykorzystany bez konieczności sprawdzania, ile miejsca będzie potrzebować po przypisaniu wartości.

PhoneNumber phoneNumber;
...
phoneNumber = "some value from somewhere";

Wreszcie usuwa zamieszanie ... czy 123 jest liczbą całkowitą czy liczbą całkowitą bez znaku? Potrzebują tej samej liczby bajtów, ale maksymalna wartość przechowywana w zmiennych dowolnego typu jest bardzo różna ...

Nie oznacza to, że jawne jest lepsze niż niejawne - ale projekt języka opiera się na tego rodzaju wyborach, a C # działałby inaczej z niejawnym pisaniem. PHP i javascript działałyby inaczej z jawnym pisaniem.

HorusKol
źródło
5

Ponieważ Sam jest mądrzejszy niż kompilatory. Na przykład, kiedy mówisz „daj mi numer telefonu”, nie określasz, czy chcesz prefiks kraju, czy numer kierunkowy, czy jest to numer służbowy, w którym wymagane są tylko 4 ostatnie cyfry. Ponadto, jeśli poprosisz o numer lokalnego pizzy, możesz poradzić sobie z odpowiedzią „pizza4u”.

Sam, wymyśla to z kontekstu. Chociaż kompilator może to również zrozumieć na podstawie kontekstu, Sam będzie w tym lepszy (i jest w stanie przerwać proces, prosząc o wyjaśnienia).

Istnieją dwa podstawowe podejścia do typów i zmiennych, albo zmienna ma typ, w którym to przypadku akcje, które nie są dozwolone przez typ, są zabronione i uniemożliwiają kompilację, lub wartość ma typ i akcje, które nie są dozwolone przez typ zostanie przechwycony w czasie wykonywania.

Każde podejście ma swoje zalety i wady. Ogólnie rzecz biorąc, autorzy kompilatorów starają się minimalizować wady i maksymalizować zalety. Dlatego na przykład C # pozwala var phoneNumber = GetPhoneNumber();i wydedukuje typ phoneNumber na podstawie podpisu GetPhoneNumber. Oznacza to, że musisz zadeklarować typ metody, ale nie zmienną, która otrzyma wynik. Z drugiej strony istnieją różne typy podpowiedzi / egzekwowania dla javascript. Wszystko jest kompromisem.

jmoreno
źródło
3

To kwestia sposobu przechowywania danych. Twoja interakcja z Samem byłaby lepszym porównaniem, gdybyś poprosił, żebyś mógł to zapisać, ale miał tylko osiem znaków papieru.

„Sam, daj mi numer telefonu”.

„5555555555”

„Och nie, zabrakło mi papieru. Gdybym tylko wiedział z wyprzedzeniem, o ile danych proszę, mógłbym się lepiej przygotować!”

Zamiast tego większość języków sprawia, że ​​deklarujesz typ, więc będzie wiedział i przygotuje się z wyprzedzeniem:

„Sam, jak długi jest numer telefonu?”

„Dziesięć znaków”.

„Ok, pozwól mi wziąć większy kawałek papieru. Teraz daj mi numer telefonu”.

„5555555555”

„Rozumiem! Dzięki Sam!”

Staje się jeszcze bardziej włochaty, kiedy spojrzysz na rzeczywiste podstawowe sposoby przechowywania danych. Jeśli jesteś podobny do mnie, masz zeszyt z różnymi notatkami, po prostu zapisanymi cyframi, bez kontekstu lub etykietowania czegokolwiek i nie masz pojęcia, co to znaczy trzy dni później. Jest to często problem również dla komputerów. Wiele języków ma typy „int” (int, długi, krótki, bajt) i „float” (float, double). Dlaczego to konieczne?

Cóż, najpierw spójrzmy, jak liczba całkowita jest przechowywana i ogólnie reprezentowana w komputerze. Prawdopodobnie zdajesz sobie sprawę, że na poziomie podstawowym wszystko jest binarne (1 i 0). Binarny to w rzeczywistości system liczbowy, który działa dokładnie tak jak nasz system liczb dziesiętnych. W systemie dziesiętnym liczy się od 0 do 9 (z nieskończonymi domniemanymi zerami na początku, których nie piszesz), a następnie przewijasz z powrotem do 0 i zwiększasz kolejną cyfrę, tak abyś miał 10. Powtarzaj, aż przejdziesz z 19 do 20, powtarzaj, aż przejdziesz od 99 do 100 itd.

Binarny nie jest inny, z wyjątkiem tego, że zamiast 0 do 9, liczysz od 0 do 1. 0, 1, 10, 11, 100, 101, 110, 111, 1000. Więc kiedy wpiszesz 9, w pamięci zapisanej w binarnym jako 1001. Jest to liczba rzeczywista. Można go dodawać, odejmować, mnożyć itp. W dokładnie takiej formie. 10 + 1 = 11. 10 + 10 = 100 (przewiń 1 na 0 i przenieś 1). 11 x 10 = 110 (i równoważnie, 11 + 11 = 110).

Teraz w rzeczywistej pamięci (łącznie z rejestrami) znajduje się lista, tablica, jakkolwiek chcesz to nazwać, bitów (potencjalne 1 lub 0 ') tuż obok siebie, w ten sposób logicznie zorganizowane te bity tworzą liczba większa niż 1. Problem polega na tym, co robisz z miejscami po przecinku? Nie można po prostu wstawić elementu sprzętowego między dwa bity w rejestrze, a dodanie „bitów dziesiętnych” pomiędzy każdą parą bitów byłoby zbyt drogie. Co więc zrobić?

Kodujesz to. Zasadniczo architektura procesora lub oprogramowania określa, jak to się robi, ale jednym z powszechnych sposobów jest przechowywanie znaku (+ lub -, ogólnie 1 jest ujemny) w pierwszym bicie rejestru, mantysa (przesunięty numer jednak wiele razy trzeba pozbyć się przecinka dziesiętnego) dla następnej liczby bitów X i wykładnika (liczba razy, kiedy trzeba go przesunąć) dla pozostałej części. Jest podobny do notacji naukowej.

Wpisanie pozwala kompilatorowi wiedzieć, na co patrzy. Wyobraź sobie, że zapisałeś wartość 1,3 w rejestrze 1. Po prostu wymyślimy tutaj nasz własny fantazyjny schemat kodowania, 1 bit na znak, 4 dla mantysy, 3 dla wykładnika (1 bit na znak, 2 dla wielkości). Jest to liczba dodatnia, więc znak jest dodatni (0). Nasza mantysa wyniesie 13 (1101), a nasz wykładnik wyniesie -1 (101 (1 dla ujemnego, 01 = 1)). Więc przechowujemy 01101101 w rejestrze 1. Teraz nie wpisaliśmy tej zmiennej, więc kiedy środowisko wykonawcze przejdzie do jej użycia, mówi „jasne, to jest liczba całkowita, dlaczego nie”, więc kiedy wypisuje wartość, widzimy 109 (64 + 32 + 8 + 4 + 1), co oczywiście nie jest właściwe.

Jednak nie każdy język wymaga wyraźnego wpisania. C # ma słowo kluczowe „var”, które powoduje, że typ zmiennej jest interpretowany w czasie kompilacji, a inne języki, takie jak JavaScript, są całkowicie dynamicznie wpisywane, do tego stopnia, że ​​można zapisać liczbę całkowitą w zmiennej, a następnie przypisać ją do wartości logicznej, a następnie przypisz go ponownie do łańcucha, a język będzie go śledził.

Ale kompilator, interpreter lub środowisko wykonawcze jest o wiele łatwiejsze - i często skutkuje szybszym programem, ponieważ nie musi on tracić cennych zasobów na sortowanie wszystkiego - na pytanie programisty, jaki rodzaj dane, które podajesz.

Devsman
źródło
2

Istnieją języki programowania, w których nie trzeba deklarować typów danych dla zmiennych. Istnieją nawet języki programowania, w których nie trzeba wcześniej deklarować zmiennych; możesz ich natychmiast użyć .

Problem z niezadeklarowaniem nazw zmiennych polega na tym, że jeśli przypadkowo błędnie przeliterujesz nazwę zmiennej, teraz przypadkowo utworzyłeś nową, całkowicie niepowiązaną zmienną. Więc kiedy uruchamiasz swój program, nie możesz zrozumieć, dlaczego, do cholery, ta zmienna, którą ustawiłeś, nagle nie ma w sobie nic ... Dopóki po wielu godzinach debugowania nie zdasz sobie sprawy, że źle wpisałeś cholerną nazwę! GRRR !!

Więc zrobili to, więc musisz zadeklarować nazwy zmiennych, których będziesz używać wcześniej. A teraz, gdy źle wpiszesz nazwę, pojawi się błąd czasu kompilacji, który natychmiast powie ci dokładnie, gdzie jest błąd, zanim nawet Twój program uruchomi się. Czy to nie jest o wiele łatwiejsze?

To samo dotyczy typów danych. Istnieją języki programowania, w których nie musisz deklarować, jaki typ rzeczy powinien być. Jeśli masz customerzmienną, która w rzeczywistości jest tylko nazwą klienta, a nie całym obiektem klienta, próba pobrania adresu klienta ze zwykłego zwykłego ciągu ... nie zadziała. Cały sens pisania statycznego polega na tym, że program się nie skompiluje; głośno narzeka, wskazując dokładne miejsce, w którym występuje problem. To o wiele szybsze niż uruchamianie kodu i próbowanie zrozumienia, dlaczego, do diabła, nie działa.

Wszystkie te funkcje informują kompilator o tym, co zamierzasz zrobić, dzięki czemu może sprawdzić, co faktycznie zrobiłeś, i upewnić się, że ma to sens. Dzięki temu kompilator może automatycznie lokalizować błędy, co jest dużym problemem.

(W odległej przeszłości nie musieliśmy deklarować podprogramów . Po prostu GOSUBpod konkretny numer linii. Jeśli chcesz przekazywać informacje między podprogramami, ustawiasz określone zmienne globalne, wywołujesz podprogram, a następnie sprawdzasz inne zmienne po powrocie podprogramu. Ale przerażająco łatwo jest zapomnieć o zainicjowaniu jednego z parametrów. Tak więc teraz prawie wszystkie współczesne języki programowania wymagają zadeklarowania, jakie rzeczywiste parametry przyjmuje podprogram, abyśmy mogli sprawdzić, czy podałeś je wszystkie. )

MathematicalOrchid
źródło
1
W C ++ możesz wstawić „auto x = 1” i wie, że to int. auto y = 1,2; auto z = „Z”; itp.
QuentinUK
@QuentinUK W języku C # można umieścić var x=1z podobnymi wynikami. Ale to nic; w Haskell, można napisać cały program bez podpisów typu w ogóle, ale to wszystko jest wpisane statycznie i nadal pojawiają się błędy, jeśli się pomylisz ... (choć nie dokładnie nurtu.)
MathematicalOrchid
@QuentinUK Ale jeśli napiszesz, for (auto i=0; i<SomeStdVector.size(); ++i)twój linter będzie narzekał, ponieważ wydedukował typ podpisany i przystąpisz do porównania go z typem niepodpisanym. Musisz pisać auto i=0ul(ponownie wpisując informacje o typie, więc po prostu napisz size_t i=0najpierw).
dmckee
1

Jeśli używam normalnego języka angielskiego, nie muszę podawać numeru telefonu jako int, aby go używać. Na przykład, jeśli poproszę mojego przyjaciela Sama o podanie mi jego numeru telefonu, mówię:

„Sam daj mi numer telefonu”

Nie powiedziałbym>

„Char (20) Sam daj mi numer telefonu wewnętrznego”

Dlaczego w ogóle musimy określać typ danych?

Wejdź do MathOverflow lub Theoretical Computer Science i poczytaj przez chwilę, aby dowiedzieć się, w jaki sposób ludzie komunikowali się między sobą alogrithms, gdy chcą się upewnić, że nie ma możliwości nieporozumień. Lub przeczytaj standard dla dojrzałego języka programowania.

Przekonasz się, że określenie, jakie wartości są dozwolone dla danego terminu, jest częścią naprawdę precyzyjnej praktyki komunikacyjnej, nawet między ludźmi.

Zauważyłeś, że codzienne interakcje są dość regularne, a ludzie są dość odporni na winy, więc dzięki wspólnej wiedzy uczestników nie unika się nieporozumień dotyczących numerów telefonów.

Ale czy kiedykolwiek próbowałeś usunąć numer telefonu dla kogoś z innego kraju? Czy powiedzieli ci wprost, ile razy naciskasz zero, aby dostać się do adresowania międzynarodowego? Czy powiedzieli ci swój kod kraju? Czy rozpoznałeś to jako takie? Ile cyfr się spodziewałeś? Ile dostałeś? Czy wiesz, jak grupować cyfry? A nawet jeśli grupa ma znaczenie?

Nagle problem jest o wiele trudniejszy i zapewne o wiele bardziej starałeś się, aby wyraźnie sprawdzić, czy otrzymany numer został zrozumiany w sposób, w jaki nadawca go rozumiał.

dmckee
źródło
0

Innym powodem deklarowania typów jest wydajność. Podczas gdy liczba całkowita może być zapisana w 1 bajcie, 2 bajtach lub 4, program wykorzystujący bardzo dużą liczbę zmiennych może zużywać czterokrotnie potrzebną pamięć, w zależności od tego, co zostanie zrobione. Tylko programista wie, czy mniejsze miejsce do przechowywania jest opłacalne, więc może to powiedzieć, deklarując typ.

Ponadto dynamicznie wpisywane obiekty pozwalają na wiele możliwych typów w locie. Mogłoby to spowodować pewne obciążenie „pod maską”, spowalniając program w porównaniu do trzymania się jednego rodzaju przez cały czas.

donjuedo
źródło
0

Wiele wczesnych języków programowania (zwłaszcza Fortran) nie wymagało deklarowania zmiennych przed użyciem.

Doprowadziło to do wielu problemów. Jedną naprawdę oczywistą jest to, że kompilator nie jest już w stanie wychwycić prostych błędów typograficznych prawie tak samo niezawodnie. Jeśli masz kod, który ma modyfikować istniejącą zmienną, ale ma literówkę, nadal masz całkowicie uzasadniony kod, który właśnie utworzył (i przypisał wartość) nowej zmiennej:

longVariableName = 1

// ...

longVaraibleName = longvariableName + anotherLongVariableName

Teraz, patrząc na to osobno, ponieważ już wspomniałem o literówce jako źródle problemu, prawdopodobnie dość łatwo jest znaleźć literówkę i problem tutaj. W długim programie, w którym jest on ukryty w środku wielu innych kodów, o wiele łatwiej jest go przeoczyć.

Nawet obecnie z wieloma dynamicznie wpisywanymi językami wciąż możesz łatwo uzyskać ten sam podstawowy problem. Niektóre mają pewne możliwości ostrzeżenia cię, jeśli przypiszesz zmienną, ale nigdy jej nie czytaj (co heurystycznie łapie sporo takich problemów), a inne nie mają takich rzeczy.

Jerry Coffin
źródło
0

Kiedy deklarujesz dowolną zmienną, część pamięci jest przydzielana w pamięci ,, ale maszyna (w tym przypadku komputer) nie wie już, ile miejsca musi zostać przydzielone dla tej zmiennej.

Przykład: - tworzysz program, który prosi użytkownika o wprowadzenie dowolnej liczby, w tym przypadku musisz określić typ danych, aby zapisać ten numer, w przeciwnym razie maszyna nie będzie w stanie sama ocenić, czy przydzieli 2 bajty lub 2 gigabajty , jeśli spróbuje samodzielne dokonanie alokacji może spowodować nieefektywne wykorzystanie pamięci. Z drugiej strony, jeśli określisz typ danych w swoim programie, to po kompilacji maszyna przydzieli odpowiednią przestrzeń zgodnie z potrzebą.

Atul170294
źródło
wydaje się, że nie oferuje to nic istotnego w porównaniu z punktami poczynionymi i wyjaśnionymi w poprzednich 11 odpowiedziach
gnat
1
Chodź, powinieneś jeszcze raz dokładnie przeczytać wszystkie odpowiedzi i przekonać się, że próbowałem odpowiedzieć na to pytanie w znacznie prostszy sposób, który można łatwo zrozumieć.
Atul170294
Właśnie ponownie sprawdziłem trzy najnowsze odpowiedzi, które zostały opublikowane około godzinę wcześniej, i wszystkie trzy wydają się mieć ten sam punkt i na podstawie mojej lektury wyjaśniam to w prostszy sposób niż tutaj
gnat
Chociaż nie odpowiedziałem na nagrodę za głosowanie, ale myślę, że powinieneś się dowiedzieć jednej rzeczy, powinieneś głosować odpowiedź, ponieważ może ona dawać bezużyteczne lub złe informacje i jeśli zawiera coś obraźliwego. Wszystkie odpowiedzi, które zawierają najbardziej przydatne i istotne informacje, otrzymają wyższą liczbę głosów pozytywnych, co wystarcza do rozróżnienia między odpowiedzią, odpowiedzią dobrą i najlepszą. Twoje dziecinne działanie polegające na zanotowaniu odpowiedzi bez żadnego silnego powodu zniechęci tylko innych ludzi, którzy również chcą podzielić się swoją opinią, która ich zdaniem może być przydatna dla innych
Atul170294
1
Twoja odpowiedź została prawdopodobnie odrzucona, ponieważ jest niepoprawna. Wpisywanie statyczne nie jest wymagane, aby ułatwić zarządzanie pamięcią. Istnieje wiele języków, które pozwalają na dynamiczne pisanie, a te języki / środowiska są w stanie poradzić sobie z wymienionymi problemami zarządzania pamięcią.
Jay Elston,