1.3.1 تایپ چیست؟ #
یک تایپ مشخص کننده نوع داده است، که به کامپایلر میگوید قرار است چه نوع دادهای داخل یک متغیر ذخیره گردد. زبانها انواع تایپهای مختلفی به صورت پیشفرض دارند که میتوان از آنها داخل برنامه خود استفاده کرد. ما میتوانیم تایپها را به دو دسته کلی تعریف کنیم.
1.3.1.1 تایپ ایستا (Static Type) #
زبانی مثل زبان گو یک زبان تایپ ایستا است، یعنی وقتی ما یک دادهای از نوع عددی داخل یک متغیر تعریف میکنیم داخل همان متغیر امکان اضافه کردن دادهای، غیر داده عددی وجود ندارد.
1.3.1.2 تایپ پویا (Dynamic Type) #
زبانهایی مثل PHP، JavaScript و … جزو زبانهای تایپ پویا هستند. یعنی وقتی یک متغیری از نوع عددی تعریف میکنیم میتوانیم به همان متغیر مقادیر دیگهای مثل مقادیر رشتهای اضافه کنیم.
تفاوت تایپ ایستا با پویا به نقل از آقای استقامت:
در زبانهایی مثل گو که جزو زبانهای نوع ایستا هستند، وقتی بخوایم متغیر یا ثابتی ایجاد کنیم، حتما می بایست نوع متغیر یا ثابت را به صورت مستقیم و صریح اعلان کنیم تا کامپایلر متوجه بشه که درون این متغیر یا ثابت قراره چه نوع داده ای ذخیره بشه.
به عنوان مثال در زبان گو باید بنویسیم:
var a, b int = 1, 2
و اگر نوع داده یا در این مثال(int) را مشخص نکنیم با ارور مواجه میشویم.
اکنون که این دو متغیر از نوع int اعلان شدند، فقط و فقط میتوان مقادیری از نوع اعداد صحیح را درون آنها ذخیره کرد و نمیتوان به عنوان مثال، یک رشته متنی یا اعداد اعشاری و … را درون آنها ذخیره نمود.
▪️ اما در مورد زبانهای نوع پویا مانند زبان پایتون، ما نیازی به اعلان صریح نوع متغیر نداریم. بلکه کافیست یک شناسه را به عنوان نام متغیر در نظر گرفته و مقداری را به آن انتساب دهیم. در اینجا، کامپایلر یا مفسر زبان به صورت خودکار نوع داده متغیر را بر اساس مقداری که به آن انتساب داده ایم شناسایی می کند: به عنوان مثال در زبان پایتون داریم:
n = 300
در این جا متغیر n دارای نوع int است که به صورت خودکار توسط زبان شناسایی میشود.
اکنون ما میتوانیم همین متغیر را در جاهای دیگری از کد استفاده کنیم و مقادیری از انواع دادهای دیگر به آن انتساب دهیم بدون اینکه هیچ مشکلی یا اروری پیش بیاید:
"n = "Hello
در حال حاضر متغیر n از نوع string می باشد!
برای اطلاعات بیشتر میتوانید تایپ سیستم را داخل ویکیپدیا مطالعه کنید.
1.3.2 تایپها در زبان گو #
زبان گو مثل سایر زبانها یکسری تایپهای پایه دارد که در هر بخش از کد گو میتوانید استفاده کنید. در ادامه این تایپها با مقادیر پیشفرض معرفی شده است.
تایپ | محدوده | مقدار پیش فرض یا مقدار صفر | حجم استفاده از حافظه |
---|---|---|---|
int | بستگی به معماری سیستم عامل که ۳۲ بیت یا ۶۴ بیت باشد | 0 | ۴ یا ۸ بایت |
int8 | 128- تا 127 | 0 | ۱ بایت |
int16 | 32768- تا 32767 | 0 | ۲ بایت |
int32 | 2147483648- تا 2147483647 | 0 | ۴ بایت |
int64 | 9223372036854775808- تا 9223372036854775807 | 0 | ۸ بایت |
uint | بستگی به معماری سیستم عامل که ۳۲ بیت یا ۶۴ بیت باشد | 0 | ۴ یا ۸ بایت |
uint8 | 0 تا 255 | 0 | ۱ بایت |
uint16 | 0 تا 65535 | 0 | ۲ بایت |
uint32 | 0 تا 6294967295 | 0 | ۴ بایت |
uint64 | 0 تا 18446744073709551615 | 0 | ۸ بایت |
uintptr | عدد خیلی بزرگ | 0 | ۸ بایت |
float32 | IEEE-754 | 0 | ۴ بایت |
float64 | IEEE-754 | 0 | ۸ بایت |
complex64 | - | 0+0i | ۸ بایت |
complex128 | - | 0+0i | ۱۶ بایت |
bool | - | false | ۱ بایت |
string | - | " " | ۱۶ بایت |
زبان گو بهطور پیشفرض از دو نوع تایپ با نام مستعار پشتیبانی میکند :
- تایپ
byte
این تایپ نام مستعار برای تایپuint8
است. - تایپ
rune
این تایپ نام مستعار برای تایپint32
است.
تفاوت int و uint در این است که نوع داده int به عنوان Signed Integer شناخته میشود و توانایی ذخیره اعداد منفی ، 0 و اعداد مثبت را دارد اما نوع داده uint به معنای Unsigned Integer بوده و فقط توانایی نگهداری اعداد مثبت و 0 را داراست.
تایپ uintptr به نقل از آقای استقامت:
در مورد نوع داده uintptr که در متن بالا در مورد آن گفته شده “عدد خیلی بزرگ"، با بیان این مطلب که چنین توضیحی نادرست است، توجه شما رو به ادامه این یادداشت جلب میکنم:
کلمه uintptr همانطور که قابل حدس زدن است کوتاه شده Unsigned Integer Pointer است.
از این نوع داده برای ذخیره و نگهداری آدرسهای حافظه(RAM) استفاده میشود.
فضایی که این نوع داده در سیستم اِشغال میکند، به نوع معماری سیستم عامل بستگی دارد.
و در نهایت، به جای عبارت “عدد خیلی بزرگ” که مفهوم اشتباه و نادرستی میرساند، باید اینگونه بگوییم که این نوع داده به اندازه کافی بزرگ است تا بتواند اشاره گرهایی(Pointers) به هر آدرس از حافظه را درون خودش ذخیره کند.(منبع)
1.3.3 سفارشیسازی تایپ(ها) #
- نامگذاری جدید : برای تایپهای رشتهای، عددی و بول، میتوان نام سفارشی جدید انتخاب و در پروژه استفاده کرد:
1
2/* type alias */
3
4// bul and bool define the same type.
5type bul = bool
6// content and string define the same type.
7type content = string
8// UI8, uint8 and byte define the same type.
9type UI8 = uint8
10// Word, rune and int32 define the same type.
11type Word = rune
- ایجاد تایپ جدید معادل یک تایپ موجود : همچنین میتوان از تایپهای موجود، یک نمونه جدید ایجاد کرد:
1/* type definition */
2
3// state and bool are two different types.
4type state bool
5// str and string are two different types.
6type str string
7// ID and uint64 are two different types.
8type ID uint64
9// decimal and float32 are two different types.
10type decimal float32
1.3.4 مقدار پیش فرض تایپها #
مقدار پیشفرض تایپها در زبان گو به شرح زیر است :
- مقدار پیشفرض تایپ بولین false است.
- مقدار پیشفرض تمامی تایپ اعداد (int, uint, float) صفر است.
- مقدار پیشفرض تایپ string برابر با رشته تهی یا empty string است .
رشته تهی معادل عبارت "" است (دو علامت نقل قول بدون هیچ کاراکتری در بین آنها) و عبارت " “ که دارای یک فاصله خالی(Space) در بین دو نقل قول است، یک رشته تهی نیست و بنابراین اشتباه است!
1.3.5 انواع مقادیر تایپها #
در زبان گو تایپها یکسری مقادیر مختلفی را دریافت میکنند که در زیر به این مقادیر میپردازیم.
1.3.5.1 تایپ بولین #
تایپ بولین فقط true
و false
را به عنوان مقدار دریافت میکند.
1.3.5.2 تایپ Integer #
تایپ اعداد ۴ نوع مقدار مختلف دریافت میکند که به ترتیب Decimal (پایه ۱۰), Octal (پایه ۸), Hex (پایه ۱۶) و Binrary (پایه ۲ یا دودویی) است.
10xF // the hex form (starts with a "0x" or "0X")
20XF
3
4017 // the octal form (starts with a "0", "0o" or "0O")
50o17
60O17
7
80b1111 // the binary form (starts with a "0b" or "0B")
90B1111
10
1115 // the decimal form (starts without a "0")
1.3.5.3 تایپ Float #
تایپ Float چند نوع مقدار را دریافت میکند که به ترتیب مقدار ممیز شناور اعشاری ممکن است شامل یک قسمت صحیح اعشاری، یک نقطه اعشاری، یک قسمت کسری اعشاری، و یک قسمت توانی عدد صحیح (مبتنی بر 10) باشد.
11.23
201.23 // == 1.23
3.23
41.
5// An "e" or "E" starts the exponent part (10-based).
61.23e2 // == 123.0
7123E2 // == 12300.0
8123.E+2 // == 12300.0
91e-1 // == 0.1
10.1e0 // == 0.1
110010e-2 // == 0.1
120e+5 // == 0.0
1.3.5.4 تایپ rune #
تایپ rune یک تایپ با نام مستعار int32 است که از تایپهای اعداد صحیح خاص هستند. از rune میتوان برای ذخیره کاراکترهای یونیکد استفاده کرد که در مثال زیر چند نمونه قرار داده شده است:
1// 141 is the octal representation of decimal number 97.
2'\141'
3// 61 is the hex representation of decimal number 97.
4'\x61'
5'\u0061'
6'\U00000061'
1package main
2
3func main() {
4 println('a' == 97)
5 println('a' == '\141')
6 println('a' == '\x61')
7 println('a' == '\u0061')
8 println('a' == '\U00000061')
9 println(0x61 == '\x61')
10 println('\u4f17' == '众')
11}
◾️استاندارد یونیکد، مجموعهای از تمام کاراکترهای موجود در جهان است (کاراکترهای زبانهای لاتین، فارسی، عربی، چینی و …، اموجیها (مانند😊)، کاراکترهای غیرقابل نمایش و …).
◾️هر کدام از این کاراکترها در استاندارد یونیکد، توسط یک عدد یکتا و منحصر به فرد مشخص شده است. به این عدد Unicode Code Point میگویند.
◾️به عنوان مثال، کد پوینت کاراکتر «😊» برابر است با U+1F60A یا کد پوینت کاراکتر «ن» در زبان فارسی برابر است با U+0646.
◾️این کد پوینتها دقیقا همان چیزهایی هستند که در runeها ذخیره میشوند.
◾️از آنجا که زبان گو، از استاندارد UTF-8 (ارائه شده توسط کنسرسیوم یونیکد) برای encoding کاراکترها استفاده میکند و در این استاندارد، هر کاراکتر فضایی بین 1 تا 4 بایت(8 بیت تا 32 بیت) را در حافظه اِشغال میکند. به همین دلیل نوع داده rune یک نام مستعار برای نوع داده int32 در زبان گو است.
1package main
2import "fmt"
3
4func main() {
5 var r rune = 'k'
6 fmt.Printf("%c %T %U", r, r, r)
7}
1.3.5.5 byte، string و rune #
مقادیر string و rune[] قابل تبدیل به یک دیگر هستند. اما تفاوت این دو در چیست؟ هر string از مجموعه ای از byte ها تشکیل شده که هر یک 8 بیت هستند. هر کاراکتر در UTF-8 از 1 تا 4 بایت تشکیل شده. مثلا حرف ‘a’ از یک بایت و کاراکتر ‘你’ از 3 بایت تشکیل میشه. به کد زیر توجه کنید:
1package main
2
3import "fmt"
4
5func stringAndRuneCompare() {
6 s := "hello你好"
7 fmt.Printf("%s, type: %T, len: %d\n", s, s, len(s))
8
9 rs := []rune(s)
10 fmt.Printf("%v, type: %T, len: %d\n", rs, rs, len(rs))
11
12}
13
14func main() {
15 stringAndRuneCompare()
16}
خروجی:
hello你好, type: string, len: 11
[104 101 108 108 111 20320 22909], type: []int32, len: 7
طول رشته در تایپ string یازده و در تایپ rune[] برابر 7 است. علت چیست؟ رشته در تایپ string یازده است، زیرا 5 نویسه اول هر کدام فقط 1 بایت می گیرند، در حالی که 2 نویسه چینی آخر هر کدام 3 بایت می گیرند. بنابراین، کل بایت 3 * 2 + 1 * 5 = 11 است.
هنگام تبدیل رشته به rune[]، گو 7 کاراکتر 32 بیتی پیدا می کند. از انجایی که هر rune برابر 32 بیت است، کاراکتر های انگلیسی و چینی هر کدام یک rune را اشغال می کنند. در نتیجه مجموعا 7 rune وجود دارد.
1.3.5.6 تایپ رشته (string) #
در زبان گو مقدار تایپ رشته بطور پیشفرض از نوع یونیکد UTF-8 است.
همچنین رشته از کارکترهای خاص یونیکد مانند 0x0D
پشتیبانی میکند.
1.3.6 خوانایی بهتر اعداد با _ #
در زبان گو میتوان برای خوانایی بهتر اعداد چند رقمی، از _
برای جداسازی استفاده کرد.
1// Legal ones:
26_9 // == 69
30_33_77_22 // == 0337722
40x_Bad_Face // == 0xBadFace
50X_1F_FFP-16 // == 0X1FFFP-16
60b1011_0111 + 0xA_B.Fp2i
7
8// Illegal ones:
9_69 // _ can't appear as the first character
1069_ // _ can't appear as the last character
116__9 // one side of _ is a illegal character
120_xBadFace // "x" is not a legal octal digit
131_.5 // "." is not a legal octal digit
141._5 // "." is not a legal octal digit