In-depth internals, my personal notes, example codes and projects. Includes - Thousands of codes, OOP, Concurrency, Parallelism, Goroutines, Mutexes & Wait Groups, Testing in Go, Go tool chain, Backend web development, Some projects including Log file parser using bufio.Scanner, Spam Masker, Retro led clock, Console animations, Dictionary programs, Social Network built using Go and GopherJS, Database Connectivity and working (MySQL, MongoDB, Redis), GopherJS and lot more..
Aditya Hajare (Linkedin).
WIP (Work In Progress)!
Open-sourced software licensed under the MIT license.
+ Environment Configurations
+ VS Code Configurations
+ Packages
- Executable Packages
- Library Packages
+ Function init()
+ Scopes
+ Renaming Imports
+ Exporting
+ Data Types
- Basic Data Types
+ Variables
- Zero Values
- Unused variables
- Multiple Declarations
- Type Inference
- Short Declaration
- Multiple Short Declarations
- Redeclarations With Short Declarations
+ Blank Identifier
+ fmt.Printf and fmt.Sprintf Formatting
+ Slice Vs. Array - Performance
+ Composite Types In Go
+ Important Links
+ Predeclared Types
+ Defined Types
+ Aliased Types
+ Important Links
+ Constant Types
+ Multiple Constants Declaration
+ Typeless Or Untyped Constants
+ Default Types
+ IOTA
+ Common Abbreviations Used In Go
+ nil
+ Important Links
+ Strings Runes And Bytes 101
+ Maps 101
+ Inheritance vs. Composition
+ Structs 101
+ Methods
+ Pointer Receivers
+ Attaching Methods To Any Types
+ Interfaces
+ Type Assertion
+ Empty Interface
+ Type Switch
+ Concurrency
+ Parallelism
+ Concurrency vs. parallelism
+ Advantages of Goroutines over Threads
+ Buffered Channels
+ Mutexes
+ Wait Groups
+ Environment Configurations
.profile
or .zshrc
or .bashrc
depending on our OS and add/edit following:
#!/bin/bash
# Specifies where the Go destribution is installed on the system.
export GOROOT=/usr/local/go
# Specifies top-level directory containing source code for all our Go projects.
# Inside this directory, we need to create 3 more directories viz. "src", "pkg" and "bin".
export GOPATH=~/adiwork/go # This directory is also known as Go Workspace.
# "src" directory inside Workspace represents where all the Go source code will be stored.
# "pkg" directory inside Workspace represents where the compiled Go packages will be stored.
# "bin" directory inside Workspace represents where the produced Go compiled binaries will be stored.
# Specifies where Go should install compiled binaries.
export GOBIN=${GOPATH}/bin
# Attaching GOROOT and GOBIN to shell environment's path variable.
export PATH=${PATH}:/usr/local/bin:${GOROOT}/bin:${GOBIN}
stringer
:
go get -u golang.org/x/tools/cmd/stringer
+ VS Code Configurations
{
"go.lintTool": "golangci-lint",
"go.formatTool": "goimports",
"go.useLanguageServer": true,
"go.lintOnSave": "package",
"go.vetOnSave": "package",
"go.vetFlags": [
"-all",
"-shadow"
]
}
strongly typed
language. Because of that, it helps Go compiler to identify many types of errors at compile time
even before our program is run.+ Packages
There are 2 kinds of packages in Go:
Executable Packages
andLibrary Packages
.
main
. It's a special package.package
clause can be used only once per file and it should be the first line in .go
source file.Go
files belonging to same folder.command-line
, must declare package main
.package main
import fm "fmt" // Package "fmt" has been aliased as "fm"
func main() {
//
}
- Executable Packages
package main
.Executable Package
should also contain main()
function and that too only once.running
it as a Go program.main
.- Library Packages
Go Standard Library Packages
are of type Library Packages
.import
them.reusability
purposes.main()
. To avoid confusion, it's better not to have function named main()
in a reusable package.+ Function init()
init()
function is used to initialize
the state of a package
.init()
function before
calling command-line
package's main()
function.+ Scopes
package
: Each Go package has it's own scope
. For e.g. declared funcs
are only visible
to the files belonging to same package
.file
: Imported packages are only visible to the importing file. Each file has to import external packages on it's own.func
.block
.+ Renaming Imports
package main
import "fmt"
import adi "fmt" // Imported "fmt" package and renamed it to "adi"
func main() {
adi.Println("नमस्ते आदित्य") // This will print "नमस्ते आदित्य"
}
+ Exporting
package aditest
func Adi() { // 'Adi()' will be exported and will be available throughout 'aditest' package
// Code..
}
func adiNew() { // 'adiNew()' will not be exported since it's name doesn't start with uppercase letter.
// Code
}
+ Data Types
literal
means the value
itself. Unline variable
, a literal
doesn't have a name.- Basic Data Types
// Integer Types
uint8 // Unsigned 8-bit integers (0 to 255)
uint16 // Unsigned 16-bit integers (0 to 65535)
uint32 // Unsigned 32-bit integers (0 to 4294967295)
uint64 // Unsigned 64-bit integers (0 to 18446744073709551615)
int8 // Signed 8-bit integers (-128 to 127)
int16 // Signed 16-bit integers (-32768 to 32767)
int32 // Signed 32-bit integers (-2147483648 to 2147483647)
int64 // Signed 64-bit integers (-9223372036854775808 to 9223372036854775807)
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Floating Types
float32 // IEEE-754 32-bit floating-point numbers
float64 // IEEE-754 64-bit floating-point numbers
complex64 // Complex numbers with float32 real and imaginary parts
complex128 // Complex numbers with float64 real and imaginary parts
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Other Numeric Types
byte // same as uint8
rune // same as int32
uint // 32 or 64 bits
int // same size as uint
uintptr // an unsigned integer to store the uninterpreted bits of a pointer value
bool // Represents 'true' or 'false'
null
in Go.string
is in effect is a read-only slice of bytes (immutable).+ Variables
compile time safety
.compile time
. They are created at run time
.pointers
(like in C).- Zero Values
zero value
to it based on it's variable type.zero value
it will take initially when declared (and if it isn't assigned any value at the time of declaration).
// Zero Values assigned to variables by Go when they are declared and not assigned any values at the time of declaration.
var adiBool bool // false
var adiInt int // 0
var adiFloat float64 // 0
var adiStr string // ""
var adiPointer *string // nil | 'nil' means it doesn't point to any memory location
- Unused variables
blocked scope
are not allowed in Go since they cause maintenance nightmares
. If we declare a variable in blocked scope
then we must use it or else completely remove it from the block. We cannot have unused variables declared in blocked scope
dangling in our source codes. Go throws unused variable errors at compile time
only.package level
variables. Go doesn't throw unused variable errors
at compile time
for variables declared at package level
.- Multiple Declarations
different types
in a single statement:
package main
func main() {
var (
adiBool bool
adiInt int
adiFloat float64
adiStr string
adiPointer *string
)
}
same type
in a single statement:
package main
func main() {
var foo, bar, baz int
}
- Type Inference
Type Inference
means Go can figure out the type of a variable automatically from it's assigned value.type
specification.package main
main() {
var someFlag = true // We are not specifying type of 'someFlag' as bool here.
}
- Short Declaration
Type Inference
, Go can figure out variable type based off it's assigned value.Short Declaration
, we can declare variable by completely ommitting var
keyword along with it's variable type.declares
and initializes
the variable.Short Declaration
syntax to declare variables in Package Scope
.Package Scope
, all declarations should start with a keyword
. Since Short Declaration
syntax doesn't have any keyword
in it, it doesn't work at Package Scope
.package main
main() {
someFlag := true // 'var' keyword and 'variable type' is not specified. It works!
}
- Multiple Short Declarations
multiple variables
of different types
using short declaration
syntax:
package main
main() {
someFlag, age, name := true, 30, "आदित्य" // Multiple variables of different types.
}
- Redeclarations With Short Declarations
Short Declaration
can initialize new variables and assign to existing variables at the same time.Short Declaration Redeclaration
must be a new variable.package main
main() {
var someFlag bool
// someFlag := true // Error! At least one variable must be new to make this work.
someFlag, age := true, 30 // This works! Because 'age' is a new variable being declared in the same statement. someFlag will be set (redeclared) to true.
}
+ Blank Identifier
“There are only two hard things in Computer Science: cache invalidation and naming things”. Tim Bray quoting Phil Karlton
unused variables
in blocked scope
.Blank Identifier (_)
is used as a variable name in Go._
._
.+ fmt.Printf and fmt.Sprintf Formatting
fmt.Printf
as well as fmt.Sprintf
:
// String and slice of bytes
%s // the uninterpreted bytes of the string or slice
%q // a double-quoted string safely escaped with Go syntax
%x // base 16, lower-case, two characters per byte
%X // base 16, upper-case, two characters per byte
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Boolean
%t // the word true or false
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// General
%v // The value in a default format. When printing structs, the plus flag (%+v) adds field names.
%#v // a Go-syntax representation of the value
%T // a Go-syntax representation of the type of the value
%% // a literal percent sign; consumes no value
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Integer
%b // base 2
%c // the character represented by the corresponding Unicode code point
%d // base 10
%o // base 8
%q // a single-quoted character literal safely escaped with Go syntax
%x // base 16, with lower-case letters for a-f
%X // base 16, with upper-case letters for A-F
%U // Unicode format: U+1234; same as "U+%04X"
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// The default format for %v
bool // %t
int, int8 // %d
uint, uint8 // %d, %x if printed with %#v
float32, complex64 // %g
string // %s
chan // %p
pointer // %p
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Floating-point and complex constituents
%b // decimalless scientific notation with exponent a power of two, in the manner of strconv.FormatFloat with the 'b' format, e.g. -123456p-78
%e // scientific notation, e.g. -1.234456e+78
%E // scientific notation, e.g. -1.234456E+78
%f // decimal point but no exponent, e.g. 123.456
%F // synonym for %f
%g // %e for large exponents, %f otherwise
%G // %E for large exponents, %F otherwise
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Floating-point Precision
%f // default width, default precision
%9f // width 9, default precision
%.2f // default width, precision 2
%9.2f // width 9, precision 2
%9.f // width 9, precision 0
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Pointer
%p // base 16 notation, with leading 0x
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Other flags
+ // always print a sign for numeric values; guarantee ASCII-only output for %q (%+q).
- // pad with spaces on the right rather than the left (left-justify the field).
# // alternate format: add leading 0 for octal (%#o), 0x for hex (%#x); 0X for hex (%#X); suppress 0x for %p (%#p); for %q, print a raw (backquoted) string if strconv.CanBackquote returns true;
' ' (space) // leave a space for elided sign in numbers (% d); put spaces between bytes printing strings or slices in hex (% x, % X).
0 // pad with leading zeros rather than spaces; for numbers, this moves the padding after the sign.
+ Slice Vs. Array - Performance
Slice
operations are cheap!Slicing
: Creates a new slice header
.Assigning a Slice to another Slice
or, passing it to a function
: Only copies the slice header
.Slice header has a fixed size
and it doesn't change
even if we have got millions of elements.Array
can be expensive as compared to Slice
.Assigning an array to another array
or passing it to a function
: Copies all the elements of it.+ Composite Types In Go
Composite Types
in Go:
Indexable
and Fixed Length
.Indexable
and Dynamic Length
.Indexable Key-Value Pairs
.compile time
, a Go compiler
can catch overflow errors
.overflows
occurs:
integer
wrap arounds and go to their minimum and maximum values.float
wrap arounds to positive infinity
or negative infinity
.+ Important Links
+ Predeclared Types
predeclared type
is a built-in type
that we can use everywhere without importing
any package
.built-in type
means it's a core feature of Go
i.e. it comes with compiler
itself.predeclared type
has a name and we can use it in any scope
.declare
a predeclared type
before using it.type representation
i.e. how Go see it and how we can use it. In other words, what values a type can represent
.size in bytes
i.e. how much space it needs in memory and it also determines the range of values it can represent.overflow errors
in runtime
. For e.g. A variable
belongs to runtime
and it's value cannot be known at the compile time
.overflow
, they gets wrapped around i.e. They get reassigned to the minimum value their variable type
can represent.Predeclared Types
:
bool // 'bool' is a predeclared type and it has following characteristics:
// Name: bool
// Representation: 'true' or 'false'
// Size: 1 byte
int // 'int' is a predeclared type and it has following characteristics:
// Name: int
// Representation: -1, 0, 1, 1000000000000000
// Size: 8 byte
+ Defined Types
Defined Type
is also called as Named Type
.Defined Type
can only be created from another existing Type
.Defined Type
can optionally have it's own methods
.type
can be converted
to another type
if they share
the same underlying type
and vice versa.defined type
and it's source type
share the same underlying type
.// 'Duration' is the 'defined type' or 'named type'.
// 'int64' is the 'underlying type'.
type Duration int64
// Type conversion
var microSeconds int64 // 'microSeconds' variable is of type 'int64'
var nanoSeconds Duration // 'nanoSeconds' variable is of type 'Duration'
nanoSeconds = microSeconds // ERROR! This won't work. To make it work:
nanoSeconds = Duration(microSeconds) // Works! We are converting 'microSeconds' to 'Named Type' we have created above i.e. 'Duration'
microSeconds = int64(nanoSeconds) // This also works!
+ Aliased Types
byte
and uint8
are exactly the same types
just with diferent names
.rune
and int32
are exactly the same types
just with diferent names
. i.e. rune
is an alias
of int32
. The rune
type is used to represent unicode characters
.Type Alias
declaration is not for everyday usage. It is mainly used in very huge codebase refactors.Constants
belong to compile time
. They must be initilized with value when they are declared.Constants
are created at compile time
. In the run time
, Go just transforms it into a value
.basic literals
are unnamed constants
. Following are examples of basic literals
:
// Unnamed constants
1
3.14
"hello"
true
false
named constants
will be replaced to their values
in runtime
. They need to be declared
first.Constants
may or may not have a type.named constants
.immutable
i.e. we cannot change their values.cannot initialize
a constant to a runtime value
.expressions
while initializing constants
.+ Important Links
+ Constant Types
non-numeric
types as well.numeric values
.don't have to
declare the types
of constants.func main() {
// Below works..
const min int = 1
const pi float64 = 3.14
const version string = "2.0.3"
const debug bool = true
// Declaring constants without types also works.
const min = 1
const pi = 3.14
const version = "2.0.3"
const debug = true
// We can use expressions while initializing constants.
const min = 1 + 1 //2
const pi = 3.14 * min // 6.28
const version = "2.0.3" + "-beta" // 2.0.3-beta
const debug = !true // false
}
+ Multiple Constants Declaration
Constants
get their types
and expressions
from the previous constant
.multiple constants
in a single go as below:
func main() {
// Multiple constants of same type in one go
const min, max int = 1, 1000
// Declaring in group
const (
min int = 1
max int = 1000
)
// Constants get their types and expressions from the previous constant
const (
min int = 1000 // 1000
max // 1000
)
}
+ Typeless Or Untyped Constants
a constant without a type
, it becomes untyped constant (typeless constant)
.basic literals
are also typeless
. They all are typeless constant values
.constant with a type
can only be used with a value
of the same type
.untyped numeric constant
can be used with all numeric values
together.func main() {
const min = 42
var i int = min // Type of constant 'min' = int
var f float64 = min // Type of constant 'min' = float64
var b byte = min // Type of constant 'min' = byte
var j int32 = min // Type of constant 'min' = int32
var r rune = min // Type of constant 'min' = rune
}
+ Default Types
Conversion
only happens when a type is needed
.converts
a typeless constant
to a typed
value when a type
is needed.func main() {
const min int32 = 1000
max := 5 + min // Type of 'max' is 'int32'
// Internally this happens: max := int32(5) + min
}
implicitly converts
the typeless constant
to a typed value
.func main() {
const min = 1000
max := 5 + min // Type of 'max' is 'int'
// Internally this happens: max := int(5) + int(min)
}
untyped constant
has a default type
.evaluates the expression
then it converts
the resulting typeless value
to its default value
.+ IOTA
IOTA
is nothing but a number generator
for constants
. In other words, it is ever increasing automatic counter.IOTA
is built-in constant generator
which generates
ever increasing numbers
.IOTA
starts at 0
.expressions
with IOTA
. So, the other constants
will repeat
the expressions
.func main() {
const (
EST = -(5 + iota) // -5
_ // -6 | Discarded/skipped due to blank identifier
MST // -7
PST // -8
)
}
+ Common Abbreviations Used In Go
var s string // string
var i int // index
var num int // number
var msg string // message
var v string // value
var val string // value
var fv string // flag value
var err error // error value
var args []string // arguments
var seen bool // has seen?
var parsed bool // parsing ok?
var buf []byte // buffer
var off int // offset
var op int // operation
var opRead int // read operation
var m int // another number
var c int // capacity
var c int // character
var sep string // separator
var src int // source
var dst int // destination
var b byte // byte
var b []byte // buffer
var buf []byte // buffer
var w io.Writer // writer
var r io.Reader // reader
var pos int // position
// ...list goes on and on...
package scope
.mixedCaps
.API
.underscores
in names.nil
value is extensively used for Error Handling.func main() {
data, err := someFunc()
if err != nil {
fmt.Println("Error occurred")
return
} else {
fmt.Println("Success")
}
}
+ nil
nil
is a predeclared identifier
like true
, false
, len()
, int32
, float64
etc.predeclared identifier
, it can be used anywhere without importing
any package
.nil value
means that the value is not initialized
yet.null // JavaScript
None // Python
null // Java
nil // Ruby
zero value
of all pointer-based
types in Go is nil
. Following are the pointer-based
types in Go:
pointers
slices
maps
interfaces
channels
nil
value can be untyped
or typed
depending on the context
.+ Important Links
+ Strings Runes And Bytes 101
string value
is nothing but a series of bytes
.string value
as a byte slice
. For e.g.
"hey" // String value
[]byte{104, 101, 121} // Representing string "hey" in byte slice
[]byte("hey") // Converting string "hey" into byte slice
string([]byte{104, 101, 121}) // Converting byte slice into string value
numbers
(byte slice), we can also represent string characters
as rune literals
.Numbers
and Rune Literals
are the same thing.Unicode Code Points
are called Runes
.Rune literal
is a typeless integer literal
.Rune literal
can be of any integer type
. for e.g. byte (uint8)
, rune (int32)
or any other integer type
.Rune
is a Unicode Code Point
that is represented by an Integer Value
.UTF-8
we can represent Unicode Code Points
between 1 byte
and 4 bytes
.Unicode Code Point
using the Rune Type
because it can store 4 bytes
of data. For e.g.
char := '��'
String values
are read-only byte slices
i.e.
string value ----> read-only []byte
String to Byte Slice
conversion creates a new []byte slice
and copies the bytes of the string to a new slice's backing array
. They don't share the same backing array
.String
is an immutable byte slice
and we cannot change any of it's elements. However, we can convert string to a byte slice
and then we can change that new slice
.string
is a data structure that points to a read-only backing array
.UTF-8
is a variable length encoding
(for efficiency). So each rune
may start at a different index
.for range
loop jumps over the runes of a string
, rather than the bytes of a string
. Each index
returns the starting index
of the next rune
.Runes
in a UTF-8 encoded string
can have a different number of bytes
because UTF-8
is a variable byte-length encoding
. UTF-8 strings
by indexes
easily. However, Go doesn't allow us to do so by default
because of efficiency reasons.[]rune(string)
creates a new slice
, and copies each rune
to new slice's backing array
. This is inefficient way of indexing strings.string
value usually use UTF-8
so it can be more efficient because each rune
on the other hand uses 1 to 4 bytes
(variable-byte length).rune
in []rune
(Rune Slice) has the same length i.e. 4 bytes
. It is inefficient because the rune
type is an alias to int32
.source code file
is encoded into utf-8
then String Literals
in our file are automatically encoded into utf-8
.bytes
, continue working with bytes
. Do not convert a string
to []byte
(Byte Slice) or vice versa, unless necessary. Prefer working with []byte
(Byte Slice) whenever possible. Bytes
are more efficient and used almost everywhere in Go standard libraries.+ Maps 101
Maps
allows us to quickly access to an element/value
using a unique key
.Map keys
must be unique
because otherwise it can't find the corresponding values/elements
.Map Keys
and Values in Maps
can be different
.Map Key
must be a comparable type
.Map Keys
and Map Values
must belong
to their corresponding types
. They can't be mixed up
.Map Variable (or a Value)
is nothing but a pointer
to a Map Header Value
in the memory
.Map Value
only contains the memory address
of a Map Header
.+ Inheritance vs. Composition
+ Structs 101
Structs
are blueprints
— They are fixed
at compile-time
.class
in OOP
languages. Groups related data
in a single type
.Struct types
are created at compile-time
.struct
may store different types
of data.Struct fields
are declared at compile-time
. However, struct values
fill them in runtime
.field names
and types
are declared at compile-time
. They are fixed
and cannot change in runtime
.Field values
belong to runtime
. We can change them in runtime
.Structs
cannot dynamically grow
but they can have different
set of types
.type VideoGame struct {
Title string Genre string
Published bool
}
structs
are equal
if all their fields
are equal
.Anonymous Fields
: When the field names conflict
the parent type
takes priority
.+ Methods
Methods
enhance types
with additional behavior.Methods
of the type
are called Method Set
.type
:
// Syntax
// "varName Type" is called a "receiver"
func (varName Type) funcName() {
// Code
}
// Example
// "book" is a struct here
func (b book) printBook() {
fmt.Println(b.title, b.price)
}
receiver
is nothing but method's input parameters
written before
a method name
.method
belongs to a single type
.Methods
on different types
can have the same names
.Method Expressions
allows us to call methods
through types
. For e.g.
// "game" is a struct type
game.print(cod)
game.print(battlefield)
method
is a function
that takes receiver
as it's first argument
.+ Pointer Receivers
methods
on types
using Pointer Receivers
.method
and a function
is that a method
belongs to a type
, whereas a function
belongs to a package
.methods
in any type
are using pointer receiver
, it is better to convert all method receivers
of that type
to pointer receivers
.pointer receiver
when we want to make changes to a receiver variable
. In other words, use a pointer receiver
when the received value into method
is going to be very large.+ Attaching Methods To Any Types
// Basic Types
int
string
float64
// Bare Types
array
struct
// -----------------------
// Do not use "Pointer Receivers" with below types since they already carry a pointer with themselves.
// i.e. slice, map, chan, func
// -----------------------
// Pointer Bearing Types
slice
map
chan // Channels
// We can also attach methods to:
func
+ Interfaces
Interface
much like as we define a user defined type
.Interfaces
decouple different types
from each other so we can create more maintainable programs.Interface
is a Protocol
, a Contract
.Interface
the weaker the abstraction
. --> Rob Pike
abstract type
. It doesn't have any implementation. It only describes the expected behavior
.Abstract Type
is Concrete Type
.types
in Go except Interface
are of Concrete Type
.Concrete Types
:
// Concrete Types
int
string
float64
array
struct
slice
map
chan
func
A Type satisfies an Interface automatically
when it has all the methods of the Interface
without explicitely specifying it.Interface
values are comparable
.Go interfaces
are implicit
. The implementing types don't need to specify that they implement an interface.type MyInterface interface {
foo() int
bar() float64
baz() string
}
+ Type Assertion
Type Assertion
allows us to extract
the dynamic value
from Interface
.Interface Value
provides the method
we want.+ Empty Interface
Empty Interface
unless really necessary.type
in Go implements the empty interface
.Interface Value
has 2 parts:
Value
.Type
.Empty Interface
is the one which doesn't have any methods
.Type
satisfies the Empty Interface
.Type
of Value
.dynamic value
of an empty interface value
.type someInterface interface {
}
value
from Empty Interface
, we first need to extract
it using Type Assertion
.Empty Interface Slice
contains the Empty Interface Values
.interface{}
can return any type
.array
, slice
, or map
using the empty interface{} type
.+ Type Switch
Type Switch
allows us to detect and extract dynamic values
from Interface Values
using Switch Statement
.Type Switch
.Type Switch
statement:
// "v" ---> Interface Value
// "type" ---> Extracts type from the Interface Value "v"
// "e" ---> Extracted value will be assigned to variable "e". It changes depending on the extracted value.
switch e := v.(type) {
case int:
// "e" is an "int" here..
case string:
// "e" is an "string" here..
default:
// "e"'s type equals to "v"'s type..
}
Switch
which compares values
, the Type Switch
compares types of the values
.+ Concurrency
Concurrency
is a way to structure a program by breaking it into pieces that can be executed independently.goroutines
).channels
).select
).Concurrency
is powerful.Concurrency
is not parallelism
.Concurrency
enables parallelism
.Concurrency
makes parallelism
(and scaling and everything else) easy.+ Parallelism
Parallelism
is the simultaneous execution of computations.+ Concurrency vs. parallelism
Concurrency
is about dealing with lots of things at once.Parallelism
is about doing lots of things at once.Concurrency
is about structure
, parallelism
is about execution
.Concurrency
provides a way to structure a solution
to solve a problem that may (but not necessarily) be parallelizable
.Concurrent
: Mouse, keyboard, display, and disk drivers.Parallel
: Vector dot product.concurrency
is achieved by using Goroutines
.Goroutines
are functions
or methods
which can run concurrently
with others methods
and functions
.Goroutines
are lightweight threads
that are managed by the Go runtime
.threads
in Java
but light weight and cost of creating them is very low.Goroutine
, we are running the function concurrently
.go
before a function call to execute it as a Goroutine
.go
.package main
import (
"fmt"
"time"
)
func print() {
fmt.Println("Printing from goroutine")
}
func main() {
go print()
time.Sleep(1 * time.Second)
fmt.Println("Printing from main")
}
main()
function execution is completed. When the program terminates, all Goroutines
are terminated regardless of the fact if all the Goroutines
has completed execution or not.Anonymous Functions
as Goroutines
as follows:
// Executing anonymous function as Goroutine
go func() {
//
}()
+ Advantages of Goroutines over Threads
Goroutines
have a faster startup time than threads
.Goroutines
come with built-in primitives
to communicate safely between themselves called as channels
.Goroutines
are extremely cheap when compared to threads
. They are only a few kb
in stack size
and the stack
can grow and shrink according to needs of the application whereas in the case of threads
the stack size
has to be specified and is fixed
.Channels
are conduits (pipes) that we can use to pass values of a particular type
from one Goroutine
to another.Channels
are a mechanism for communication.Channels
allows Goroutines
to share memory by communicatingChannel Operators: <-, ->
to send and receive values.
arrow
.Channel
using built-in make()
function as below:
ch := make(chan type) // type: Data Type
Normal Channels
are Synchronous
. i.e. Both the sending side and the receiving side of the channel
wait until the other side is ready.+ Buffered Channels
Buffered Channels
are Asynchronous
. i.e. Sending and Receiving messages through Buffered Channels
will not block unless the Channel
is full.Buffered Channel
same way as we create the Normal Channels
using the built-in make()
function. The only difference is, we can pass the second parameter to make()
function which indicates the Buffered Channel's Buffering Capacity
.ch := make(chan type, capacity)
Buffering Capacity
as 1
, we are creating a Normal Channel
. To create a Buffered Channel
, we have to pass Buffering Capacity
as greater than 1
Goroutines
run in a same address space
, they have access to shared memory
and this access
must be synchronised
. Go's motto is to share memory
by communicating
(Goroutines
and Channels
makes this possible).traditional forms of synchronisation
. Go allows us to make use of these Synchonisation Primitives
by using the Sync
package.+ Mutexes
Race Condition
happens when two or more threads
can access shared data
and try to change that shared data
at the same time. We can use Mutex
to solve this problem.Mutex
is a Mutual Exclusion Lock
. It's a Synchronisation Primitive
.protect shared data
which is simultaneously accessed
by multiple treads
.+ Wait Groups
Wait Groups
are another Synchronisation Primitive
.Wait Group
basically waits for collection
of Goroutines
to finish execution.go vet
command helps us catch errors which are not generally caught by Go Compiler.62-Go-Vet-To-Catch-Errors
go vet main.go
int
is supplied to fmt.Printf()
whereas string
value should've been supplied. This error isn't caught by Go Compiler since the program is still syntactically correct.# Install godoc with following command first:
# go get golang.org/x/tools/cmd/godoc
# Then execute:
godoc -http=:6060
http://localhost:6060
微信关注【面试情报局】我们一起干翻面试官, 回复golang获取本文源码 视频地址:b站 10节课学会Golang,Go快速入门 流程控制 循环语句 Golang中有三种类型的循环语句:for 循环、range 循环和 goto 语句。 For循环 Golang中通过For关键字来定义一个循环并且只有For关键字(Golang中没有while关键字),格式 for initialization;
微信关注【面试情报局】我们一起干翻面试官, 回复golang获取本文源码 视频地址:b站 10节课学会Golang,Go快速入门 数组与切片 在 Go 中,数组和切片是两个非常常用的数据结构。虽然它们都可以存储一系列元素,但它们之间有着很大的区别。 数组是一个固定大小的数据结构,一旦创建后,其大小就不能被改变,数组中的所有元素必须是相同的类型。 切片是一个动态大小的数据结构,它可以根据需要动态地增
golang 的fmt 包实现了格式化I/O函数,类似于C的 printf 和 scanf。 定义示例类型和变量 type Human struct { Name string }var people = Human{Name:"zhangsan"} 普通占位符 占位符 说明 举例 输出 %v
微信关注【面试情报局】我们一起干翻面试官, 回复golang获取本文源码# 变量与常量 视频地址:b站 10节课学会Golang,Go快速入门 变量与常量 变量和常量简单来说就是给内存中某一个地址起一个名字, 然后用这个地址存储某个特定类型的值。 数据类型 数据类型分类: 布尔类型:bool。 整数类型:int8、uint8、int16、uint16、int32、uint32、int64、uint
在编程过程中,我们总是要遇到这样的问题,就是将我们的数据对象要在网络中传输或保存到文件,这就需要对其编码和解码动作。 目前存在很多编码格式:json, XML, Gob, Google Protocol Buffer 等,在Go 语言中,如何对数据进行这样的编码和解码呢? 序列化和反序列化定义 序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,
1. go语言中的range 1.1 array words := []string{"Go", "语言", "高性能", "编程"} for i, s := range words { words = append(words, "test") fmt.Println(i, s) } /*结果 0 Go 1 语言 2 高性能 3 编程 */ 变量 words 在循环开始前,仅会
更多好文关注 v。golang技术实验室 1、GOGC GOGC 用于控制GC的处发频率, 其值默认为100, 意为直到自上次垃圾回收后heap size已经增长了100%时GC才触发运行。即是GOGC=100意味着live heap size 每增长一倍,GC触发运行一次。 如设定GOGC=200, 则live heap size 自上次垃圾回收后,增长2倍时,GC触发运行, 总之,其值越大则G
方法 方法能给用户自定义的类型添加新的行为。它和函数的区别在于方法有一个接收者,给一个函数添加一个接收者,那么它就变成了方法。接收者可以是值接收者,也可以是指针接收者。 在调用方法的时候,值类型既可以调用值接收者的方法,也可以调用指针接收者的方法;指针类型既可以调用指针接收者的方法,也可以调用值接收者的方法。 package main import "fmt" type Person struct
Go Module go env -w GOPROXY="https://goproxy.cn,direct" get -u:下载并安装代码包,不论工作区中是否已存在它们 -t:同时下载测试所需的代码包 编译 构建使用命令go build,安装使用命令go install 构建和安装代码包的时候都会执行编译、打包等操作,并且,这些操作生成的任何文件都会先被保存到某个临时的目录中 如果构建的是库源码
微信关注【面试情报局】我们一起干翻面试官, 回复golang获取本文源码 Goroutine Goroutine 是 Go 语言中轻量级的并发处理方式之一。它可以看作是一个轻量级线程,一个程序可以包含成百上千个 Goroutine。Goroutine 的启动非常快,只需要几纳秒的时间,而且 Goroutine 的调度是由 Go 运行时系统自动完成的,开发者不需要手动进行线程调度。 Goroutin
【1】基本理论 开闭原则的英文全称是 Open Closed Principle,简写为 OCP。即添加一个新的功能应该是,在已有代码基础上扩展代码(新增模块、类、方法等),而非修改已有代码(修改模块、类、方法等)。 【2】功能描述 假设现在有一个API接口监控告警的需求:可以根据接口配置不同的监控维度(Tps,错误数),然后发送告警通知。后续如果要新增新的维度(
golang 的fmt 包实现了格式化I/O函数,类似于C的 printf 和 scanf。 // 定义示例类型和变量 type Human struct { Name string } var people = Human{Name:"zhangsan"} 1、普通占位符: 占位符 说明 举例
golang golang 格式的 chaincode。
gosql 是一款 golang style 语法的 golang orm 库。 优雅的语法,支持批量插入; 轻松嵌套条件,处理各种复杂的查询 sql,诸如:and 和 or 组合; 全语法支持:for update 锁、is null、exists 子查询等基本上所有 sql 语法 特xing Golang-style SQL builder go语言风格sql生成 Unlimited nest
html2article — 基于文本密度的html2article实现[golang] Install go get -u -v github.com/sundy-li/html2article Performance avg 3.2ms per article, accuracy >= 98% (对比其他开源实现,可能是目前最快的html2article实现,我们测试的数据集约3kw来自于微信
Libretto 是一个 Golang 库,可在任何云和虚拟机托管平台(如 AWS,Azure,OpenStack,vSphere 或VirtualBox)上创建虚拟机(VM)。 可在下列平台部署 AWS Azure DigitalOcean Exoscale Google Cloud Platform Openstack (Mirantis) Virtualbox >= 4.3.30 VMwar
Gos 自称为 “Armed Golang(加强版的 Go)”,定位是原生 go 命令的一个“加强版”解决方案。 据官方介绍可以使用 gos 代替 go: go get => gos getgo build => gos buildgo run => gos rungo ... => gos ... 因为 gos 兼容所有的 go 命令,并且还额外增加了搭载智能 GOPROXY 的 go mod/
Go 语言实现 API 网关基础功能。(主要看重 Go 并发处理能力) 获取代码 go get -u github.com/wisrc/gateway 日志框架使用了 golang.org/x/sys 中的包,如果出现下载这个包超时的情况,请到 github.com/golang/sys 中下载,然后将 github.com/golang/sys 重命名为 golang.org/x/sys 配置介