Go Concepts - The Type System: Difference between revisions
(104 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
= | =TODO= | ||
<font color=darkkhaki>Deplete into [[Go_Language#The_Type_System]] and delete. | |||
=Overview= | =Overview= | ||
Go is ''statically typed''. Go designers tried to alleviate some of the "[[ | Go is ''statically typed''. Go designers tried to alleviate some of the "[[Programming_Languages_Concepts#Static_Typing_vs_Dynamic_Typing|heaviness]]" associated with statically typed languages and made it "feel" like a dynamic language. For example Go uses ''local type inference'', which eliminates the need to specify the type unnecessarily in program, the compiler figures it out. | ||
Go is ''strongly typed'' meaning that yes cannot be unsafely coerced into other types they're not, or at least without programmer giving explicit permission. In JavaScript, for example, implicit conversion is done based on complicated rules that are not always easy to remember. | Go is ''strongly typed'' meaning that yes cannot be unsafely coerced into other types they're not, or at least without programmer giving explicit permission. In JavaScript, for example, implicit conversion is done based on complicated rules that are not always easy to remember. | ||
For more details on typing, see [[ | For more details on typing, see [[Programming_Languages_Concepts#Static_Typing_vs_Dynamic_Typing|static typing vs. dynamic typing]] and [[Programming_Languages_Concepts#Strong_Typing_vs_Loose_Typing|strong typing vs. loose typing]]. | ||
Go provides a ''hierarchy-free'' type system - there are no classes and no class inheritance. It is still an object-oriented language. Go type system encourages ''composition'', where types are ''composed'' of smaller types. | |||
=Type Definition= | =Type Definition= | ||
<blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;"> | <blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;"> | ||
:[[ | :[[Programming_Languages_Concepts#Type|Type Definition]] | ||
</blockquote> | </blockquote> | ||
=Zero Value= | |||
''Zero value'' for a specific type: 0 for <tt>int</tt>s, 0.0 for <tt>float</tt>s, "" for <tt>string</tt>s, <tt>false</tt> for Booleans and <tt>nil</tt> for pointers (<tt>0x0</tt>). | |||
For [[#Reference_Types|reference types]], their underlying data structures are initialized to their zero values, but variable declared as a reference type set to their zero values will return a value of <tt>nil</tt>. For example, the zero value for [[Go Maps#Overview|maps]], [[Go Slices#Overview|slices]] and [[Go Channels#Overview|channels]] is <tt>nil</tt>. | |||
=Built-in Types= | =Built-in Types= | ||
The built-in types are the set of types that are provided by the language. The definition of the following types can be found in <tt>$GO_HOME/src/builtin/builtin.go</tt>: | |||
===<tt>[[Go Booleans|bool]]</tt>=== | |||
===[[Go Integers|Integers]]=== | |||
<blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;"> | <blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;"> | ||
:[[Go Integers|Integers]] | :[[Go Integers|Integers]] | ||
</blockquote> | </blockquote> | ||
===[[Go Floating Point|Floating-Point Numbers]]=== | |||
===<tt>[[Go Strings|string]]</tt>=== | |||
===[[Go Arrays|Arrays]]=== | |||
===[[Go Slices|Slices]]=== | |||
===[[Go Maps|Maps]]=== | |||
===<tt>[[Go Language Error Handling#The_error_Type|error]]</tt>=== | |||
=Function Types= | =Function Types= | ||
A function is member of a function type. The function type is defined by its signature. | A function is member of a function type. The function type is defined by its signature: | ||
<pre> | |||
func(input_param_type1, input_param_type2, ...) (return_type1, return_type2, ...) | |||
</pre> | |||
Example: < | Example of a function that requires an int and returns an int: | ||
<pre> | |||
func(int) int | |||
</pre> | |||
<pre> | <pre> | ||
Line 44: | Line 66: | ||
} | } | ||
</pre> | </pre> | ||
Also see: | |||
<blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;"> | |||
:[[Go_Concepts_-_Functions#Function_Literals|Function Literals]] | |||
</blockquote> | |||
=Pointer Types= | =Pointer Types= | ||
A ''pointer type'' denotes the set of all pointers to variables of a given type, called the ''base type'' of the pointer. | |||
Note that the base type and the associated pointer type are obviously two different types. Values of one cannot be assigned to another, and vice-versa. This is what happens when such an assignment is attempted: | |||
<pre> | |||
./main.go:24: cannot use v2 (type *B) as type B in assignment | |||
</pre> | |||
The difference between a base type and its associated pointer type is also relevant when we are discussing whether the type and its pointer type implement an interface. For a discussion on this subject, see: | |||
<blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;"> | |||
:[[Go_Interfaces#When_does_a_Type.2FPointer_Type_Implement_an_Interface.3F|When does a Type/Pointer Type Implement an Interface?]] | |||
</blockquote> | |||
A ''pointer type'' is declared using the [[Go_Concepts_-_Operators#.2A|dereference operator]] <tt>[[Go_Concepts_-_Operators#.2A|*]]</tt> placed in front of the target type - the type of the stored value: | A ''pointer type'' is declared using the [[Go_Concepts_-_Operators#.2A|dereference operator]] <tt>[[Go_Concepts_-_Operators#.2A|*]]</tt> placed in front of the target type - the type of the stored value: | ||
Line 53: | Line 95: | ||
</pre> | </pre> | ||
We cannot do pointer arithmetic. Assuming <tt>ptr</tt> is a <tt>*int</tt>, we cannot do <tt>ptr + 1</tt> and we can't do <tt>ptr + ptr2</tt>. | We cannot do pointer arithmetic. Assuming <tt>ptr</tt> is a <tt>*int</tt>, we cannot do <tt>ptr + 1</tt> (compilation error message: <tt>invalid operation: ptr + 1 (mismatched types *int and int)</tt>) and we can't do <tt>ptr + ptr2</tt> (compilation error message: <tt>invalid operation: ptr + ptr2 (operator + not defined on pointer)</tt>). | ||
For more details, see [[Go_Concepts_-_Lexical_Structure#Pointers|pointers]]. | For more details, see [[Go_Concepts_-_Lexical_Structure#Pointers|pointers]]. | ||
=User-Defined Types= | =User-Defined Types= | ||
The user-defined types are introduced by the <tt>type</tt> keyword. There are three kinds of user-defined types: 1) <tt>struct</tt>s 2) type aliasing and 3) interfaces. Behavior can be added to <tt>struct</tt>s and aliased types by the way of [[Go_Concepts_-_Functions#Methods|methods]]. | |||
The documentation sometimes refers to user-defined types as ''named types''. | |||
===[[Go Structs|Structs]]=== | |||
<blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;"> | <blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;"> | ||
:[[Go Structs| | :<tt>[[Go Structs|struct]]</tt> | ||
</blockquote> | </blockquote> | ||
== | ===[[Go Type Aliasing|Type Aliasing]]=== | ||
< | <blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;"> | ||
:[[Go Type Aliasing|Type Aliasing]] | |||
</blockquote> | |||
===[[Go Interfaces|Interfaces]]=== | |||
= | <blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;"> | ||
:[[Go Interfaces|Interfaces]] | |||
</blockquote> | |||
==Declaring Multiple Types== | |||
<pre> | |||
type ( | |||
A struct { | |||
... | |||
} | |||
B struct { | |||
... | |||
} | |||
... | |||
) | |||
</pre> | |||
=Conversion Between Types= | =Conversion Between Types= | ||
Line 89: | Line 151: | ||
</pre> | </pre> | ||
= | This is equivalent with Java cast. | ||
Note that the same syntax can be used to convert to and from user-defined types: | |||
<pre> | |||
import "time" | |||
... | |||
var sleepSeconds int | |||
sleepSeconds = 1 | |||
// | |||
// time.Sleep expects a time.Duration do we convert time.Second to int, multiply and convert back to time.Duration | |||
// | |||
var duration time.Duration | |||
duration = time.Duration(sleepSeconds * int(time.Second)) | |||
time.Sleep(duration) | |||
</pre> | |||
Also see: | |||
<blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;"> | |||
:[[Go_Integers#Conversion_between_bytes_and_strings|Conversion between bytes and strings]] | |||
</blockquote> | |||
=Reference Types= | |||
The reference types in Go are [[Go_Slices#Overview|slices]], [[Go_Maps#Overview|maps]], [[Go_Channels#channels|channels]], [[Go Interfaces|interfaces]] and [[Go Concepts - Functions|functions]]. | |||
When a variable of such a type is declared, the value that is created is called a ''header'' value. The header contains pointers to underlying data structures and a set of unique fields that are used to manage those data structures. Reference type values must not be shared, because the header values are designed to be copied: the header value contains a pointer, therefore if a copy of the header value is passed, the underlying data structure is intrinsically shared. | |||
These fields are are initialized by default to their [[#Zero_Value|zero values]]. However, variable declared as a reference type set to their zero values will return a value of <tt>nil</tt>. |
Revision as of 17:31, 20 March 2024
TODO
Deplete into Go_Language#The_Type_System and delete.
Overview
Go is statically typed. Go designers tried to alleviate some of the "heaviness" associated with statically typed languages and made it "feel" like a dynamic language. For example Go uses local type inference, which eliminates the need to specify the type unnecessarily in program, the compiler figures it out.
Go is strongly typed meaning that yes cannot be unsafely coerced into other types they're not, or at least without programmer giving explicit permission. In JavaScript, for example, implicit conversion is done based on complicated rules that are not always easy to remember.
For more details on typing, see static typing vs. dynamic typing and strong typing vs. loose typing.
Go provides a hierarchy-free type system - there are no classes and no class inheritance. It is still an object-oriented language. Go type system encourages composition, where types are composed of smaller types.
Type Definition
Zero Value
Zero value for a specific type: 0 for ints, 0.0 for floats, "" for strings, false for Booleans and nil for pointers (0x0).
For reference types, their underlying data structures are initialized to their zero values, but variable declared as a reference type set to their zero values will return a value of nil. For example, the zero value for maps, slices and channels is nil.
Built-in Types
The built-in types are the set of types that are provided by the language. The definition of the following types can be found in $GO_HOME/src/builtin/builtin.go:
bool
Integers
Floating-Point Numbers
string
Arrays
Slices
Maps
error
Function Types
A function is member of a function type. The function type is defined by its signature:
func(input_param_type1, input_param_type2, ...) (return_type1, return_type2, ...)
Example of a function that requires an int and returns an int:
func(int) int
// a variable of type func(int) int is declared var f func(int) int; // the variable is initialized with an actual function f = func(i int) int { return i + 1 }
Also see:
Pointer Types
A pointer type denotes the set of all pointers to variables of a given type, called the base type of the pointer.
Note that the base type and the associated pointer type are obviously two different types. Values of one cannot be assigned to another, and vice-versa. This is what happens when such an assignment is attempted:
./main.go:24: cannot use v2 (type *B) as type B in assignment
The difference between a base type and its associated pointer type is also relevant when we are discussing whether the type and its pointer type implement an interface. For a discussion on this subject, see:
A pointer type is declared using the dereference operator * placed in front of the target type - the type of the stored value:
*int
We cannot do pointer arithmetic. Assuming ptr is a *int, we cannot do ptr + 1 (compilation error message: invalid operation: ptr + 1 (mismatched types *int and int)) and we can't do ptr + ptr2 (compilation error message: invalid operation: ptr + ptr2 (operator + not defined on pointer)).
For more details, see pointers.
User-Defined Types
The user-defined types are introduced by the type keyword. There are three kinds of user-defined types: 1) structs 2) type aliasing and 3) interfaces. Behavior can be added to structs and aliased types by the way of methods.
The documentation sometimes refers to user-defined types as named types.
Structs
Type Aliasing
Interfaces
Declaring Multiple Types
type ( A struct { ... } B struct { ... } ... )
Conversion Between Types
In order to convert between types, the type name is used like a function:
var f float64 = 5.0 var i int = 5 ... result = f / float64(i)
This is equivalent with Java cast.
Note that the same syntax can be used to convert to and from user-defined types:
import "time" ... var sleepSeconds int sleepSeconds = 1 // // time.Sleep expects a time.Duration do we convert time.Second to int, multiply and convert back to time.Duration // var duration time.Duration duration = time.Duration(sleepSeconds * int(time.Second)) time.Sleep(duration)
Also see:
Reference Types
The reference types in Go are slices, maps, channels, interfaces and functions.
When a variable of such a type is declared, the value that is created is called a header value. The header contains pointers to underlying data structures and a set of unique fields that are used to manage those data structures. Reference type values must not be shared, because the header values are designed to be copied: the header value contains a pointer, therefore if a copy of the header value is passed, the underlying data structure is intrinsically shared.
These fields are are initialized by default to their zero values. However, variable declared as a reference type set to their zero values will return a value of nil.