Go: Go Variables and Data Types

Last updated: 2026-08-26

Variables are the cornerstone of a program—Go uses minimal syntax to make متغير declarations both clear and safe.

The design philosophy behind Go's type system: Explicit over Implicit. This means that every متغير has a well-defined type, allowing the compiler to catch more than 90% of errors at compile time. In this lesson, you'll learn all the syntax for declaring variables in Go.

1. You will learn



2. The True Story of a Full-Stack Engineer

(1) Pain Point: Late-night debugging caused by dynamic typing

Alice is an engineer who switched from Python to Go. She recently joined the company and took over a user registration module:

"The PM said, 'After the launch, the user data was all over the place. Some people entered January 1, 2024, as their date of birth, some entered "yesterday," and others entered فارغ—half the data in the قاعدة بيانات couldn't be parsed.'"

She took a look at the code and discovered that Python's dynamic typing was the culprit:

PYTHON
# Python: variable types can change at any time
birthday = "1990-01-01"
birthday = 1990  # integer suddenly valid
birthday = None  # None also valid
birthday = ["today"]  # list also valid!

The same variable can be a string, an integer, None, or a list in different parts of the code—there is no mechanism to prevent this confusion.

(2) Solution in Go

Alice rewrote the user model in Go:

GO
// user.go
package main

import "fmt"

type User struct {
    Name      string  // string
    Age       int     // integer
    Height    float64 // float
    IsActive  bool    // boolean
    Birthday  string  // ISO 8601 date string
}

func main() {
    user := User{
        Name:     "Alice",
        Age:      28,
        Height:   165.5,
        IsActive: true,
        Birthday: "1996-05-12",
    }

    // Want to change `Age` to a string? You'll get a compile-time error!
    // user.Age = "twenty-eight"  // ❌ cannot use "twenty-eight" as int

    fmt.Printf("User: %s, Age: %d, Height: %.1fcm\n",
        user.Name, user.Age, user.Height)
}

Output:

TEXT 📖 Display only
User: Alice, Age: 28, Height: 165.5cm

(3) Benefits: Captures 90% of errors during compilation

Dimension Python (dynamically typed) Go (statically and strongly typed)
Compile-time type checking ❌ None ✅ Strict
Runtime Type Error Frequent Rare
IDE Auto-Complete Weak Strong
Refactoring Safety Low High
Null Value Trap (None/null) Common Zero-Value Mechanism Protection
💡 Tip: Go's "zero-value mechanism" ensures that every variable has a reasonable default value upon declaration, eliminating 80% of null pointer issues.



3. Variable Declaration: var and :=

Go provides two ways to declare variables: the var keyword (standard) and the := short declaration (shorthand).

(1) var keyword declaration (standard method)

var can be used within functions or at the package level, and there are three ways to write it:

GO
// Method 1: Declare a variable with an explicit type
var name string = "Alice"

// Method 2: Declare a variable and omit the type (the type is inferred from the value)
var name = "Alice"

// Method 3: Declare only; initialize to zero value
var name string  // name = ""

▶ Example: Comparison of three ways to write var

GO
package main

import "fmt"

func main() {
    // Method 1: Explicit Type + Initialization
    var userName string = "Alice"
    var userAge int = 28

    // Method 2: Type Inference
    var userEmail = "alice@example.com"

    // Method 3: Declare only; rely on the default value
    var userBio string  // ""

    fmt.Println(userName, userAge, userEmail, userBio)
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
Alice 28 alice@example.com

(3) := Short declaration (most common)

:= is syntactic sugar in Go; it can only be used inside functions and automatically infers the type:

GO
package main

import "fmt"

func main() {
    // Short declaration: variable_name := value
    name := "Alice"       // inferred as string
    age := 28             // inferred as int
    height := 165.5       // inferred as float64
    isActive := true      // inferred as bool

    fmt.Printf("%s is %d years old, height %.1f, active: %v\n",
        name, age, height, isActive)
}

Output:

TEXT 📖 Display only
Alice is 28 years old, height 165.5, active: true

(4) var vs :=—which one should I choose?

Scenario Recommended Approach Reason
Package-level variables var := Cannot be used outside of functions
Local variables within a function := Concise; saves 4 characters
Must be zero value var x int := Must be initialized at the same time
Requires an explicit type cast var x int = int(3.14) The type cast is clearly visible
Batch declarations var (...) := does not support batch declarations


4. Go's Basic Data Types

Go has 14 basic data types, which are divided into four major categories based on their purpose.

(1) Integer Types

100%
graph TB
    A[Integer Types] --> B[Signed int]
    A --> C[Unsigned uint]
    A --> D[Byte type]
    A --> E[Special rune]

    B --> B1[int<br/>at least 32 bits]
    B --> B2[int8 / int16 / int32 / int64]

    C --> C1[uint<br/>at least 32 bits]
    C --> C2[uint8 / uint16 / uint32 / uint64]

    D --> D1[byte = uint8<br/>emphasizes byte]
    E --> E1[rune = int32<br/>emphasizes Unicode code point]
Type Size Range Typical Applications
int 32- or 64-bit (platform-dependent) -2^31 to 2^31-1 or larger Default integer type
int8 8 bits -128 to 127 Small-range integers
int32 32-bit -2^31 to 2^31-1 Cross-platform fixed size
int64 64-bit -2^63 to 2^63-1 Large integers, timestamps
uint 32- or 64-bit 0 to 2^32-1 or greater Unsigned by default
byte 8 bits 0–255 byte, ASCII character
rune 32-bit Unicode code point Single Unicode character

▶ Example: The difference between int and int64

GO
package main

import (
    "fmt"
    "unsafe"
)

func main() {
    var a int = 100
    var b int64 = 200

    fmt.Printf("a (int) size: %d bytes\n", unsafe.Sizeof(a))
    fmt.Printf("b (int64) size: %d bytes\n", unsafe.Sizeof(b))

    // You cannot directly add `int` and `int64`!
    // sum := a + b  // ❌ mismatched types int and int64

    // An explicit conversion is required
    sum := a + int(b)
    fmt.Println("sum:", sum)
}
▶ Try it Yourself

Output (on 64-bit platforms):

TEXT 📖 Display only
a (int) size: 8 bytes
b (int64) size: 8 bytes
sum: 300

(3) Floating-point types

Type Size Precision Typical Applications
float32 32 bits ~7 significant digits Scientific computing, graphics
float64 64-bit ~15 significant digits Default floating-point type

(4) Boolean Type

GO
var isActive bool = true
var hasPermission bool  // zero value = false

(5) String Type

GO
var greeting string = "Hello, Go!"
var emptyString string  // zero value = "" (empty string)
var multiLine string = `Line 1
Line 2
Line 3`  // backticks support multi-line strings

(6) Quick Reference Chart for 14 Types

Category Type Zero Value
Integer int / int8 / int16 / int32 / int64 0
Unsigned integers uint / uint8 / uint16 / uint32 / uint64 0
Byte/Character byte (=uint8) / rune (=int32) 0
Floating-point float32 / float64 0.0
Boolean bool false
String string ""


5. Go's Unique Zero-Value Mechanism

There are no "uninitialized" variables in Go—every variable has a reasonable default value when it is declared.

▶ Example: Zero values of all types

GO
package main

import "fmt"

func main() {
    var i int
    var f float64
    var b bool
    var s string
    var p *int  // pointer zero value is nil

    fmt.Printf("int: %d\n", i)
    fmt.Printf("float64: %f\n", f)
    fmt.Printf("bool: %v\n", b)
    fmt.Printf("string: %q\n", s)  // %q shows quoted string, empty string shows ""
    fmt.Printf("pointer: %v\n", p)
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
int: 0
float64: 0.000000
bool: false
string: ""
pointer: <nil>

(2) Zero Values vs. Other Languages

Type Go zero value Java Python C/C++
Integer 0 0 Does not exist Undefined (garbage value)
Floating-point 0.0 0.0 Does not exist Undefined
Boolean false false False Undefined
String "" null "" Undefined
Pointer nil null None NULL (but prone to wild pointers)
🔥 Common Mistake: In C/C++, uninitialized variables contain random values in memory—this is the root cause of 90% of buffer overflow bugs. Go eliminates this problem at the language level through its zero-value mechanism.



6. const Constants and iota Enumerations

(1) Use const to declare constants

Constants are determined at compile time, cannot be modified, and must be basic types:

GO
const Pi = 3.14159
const AppName = "web-tutorial"
const MaxConnections = 1000

(2) Iota Enumeration: Go's Elegant Enumeration

iota is a constant counter in Go that starts at 0 and automatically increments by 1 on each line:

GO
package main

import "fmt"

const (
    Sunday    = iota  // 0
    Monday            // 1
    Tuesday           // 2
    Wednesday         // 3
    Thursday          // 4
    Friday            // 5
    Saturday          // 6
)

func main() {
    fmt.Printf("Sunday=%d Monday=%d Saturday=%d\n", Sunday, Monday, Saturday)
}

Output:

TEXT 📖 Display only
Sunday=0 Monday=1 Saturday=6

▶ Example: Custom iota increment (HTTP status codes)

GO
package main

import "fmt"

const (
    StatusOK       = iota * 100  // 0
    StatusRedirect               // 100
    StatusClientError            // 200
    StatusServerError            // 300
)

func main() {
    fmt.Printf("OK=%d Redirect=%d ClientError=%d ServerError=%d\n",
        StatusOK, StatusRedirect, StatusClientError, StatusServerError)
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
OK=0 Redirect=100 ClientError=200 ServerError=300

(4) Advanced iota Usage: Bitmasks (File Permissions)

GO
package main

import "fmt"

const (
    ReadPermission   = 1 << iota  // 1 << 0 = 1
    WritePermission               // 1 << 1 = 2
    ExecutePermission             // 1 << 2 = 4
)

func main() {
    // Permission Combination: Read + Write = 1 | 2 = 3
    rw := ReadPermission | WritePermission
    fmt.Printf("Read=%d Write=%d Execute=%d RW=%d\n",
        ReadPermission, WritePermission, ExecutePermission, rw)
}

Output:

TEXT 📖 Display only
Read=1 Write=2 Execute=4 RW=3
💡 Tip: iota is the only syntax in Go that comes close to an "enum," but it isn't as strict as the enum types in Python or Java. If you need stronger type safety in a production environment, you can define your own types.



7. Explicit Type Conversion

Go does not allow implicit type conversions—all conversions must be explicitly declared. This reflects Go's "explicit over implicit" principle.

(1) Numeric Type Conversion

GO
package main

import "fmt"

func main() {
    var i int = 42
    var f float64 = float64(i)      // int → float64
    var u uint = uint(f)            // float64 → uint

    fmt.Printf("i=%d f=%v u=%d\n", i, f, u)

    // Truncation example: Converting a float to an int results in the loss of the decimal part
    var pi float64 = 3.14159
    var truncated = int(pi)
    fmt.Printf("pi=%.5f truncated=%d\n", pi, truncated)
}

Output:

TEXT 📖 Display only
i=42 f=42 u=42
pi=3.14159 truncated=3

(2) String conversion: the strconv package

GO
package main

import (
    "fmt"
    "strconv"
)

func main() {
    // String → Number
    n, err := strconv.Atoi("123")
    fmt.Printf("n=%d err=%v\n", n, err)

    // Number → String
    s := strconv.Itoa(456)
    fmt.Printf("s=%s (type: %T)\n", s, s)

    // String → float
    f, _ := strconv.ParseFloat("3.14", 64)
    fmt.Printf("f=%f\n", f)

    // float → string (specified precision)
    fmt.Println(strconv.FormatFloat(3.14159, 'f', 2, 64))  // "3.14"
}

Output:

TEXT 📖 Display only
n=123 err=<nil>
s=456 (type: string)
f=3.140000
3.14

(3) Implicit Conversion vs. Explicit Conversion

Scenario Java/C++ Go
int + float Automatically converted to float Compilation error; must be explicit
int32 + int64 Automatically converted to int64 Compilation error
int to string Implicit Requires strconv.Itoa()
⚠️ Note: Go's strict type conversion may seem verbose, but it actually prevents classic bugs found in Java and C++, such as "rounding errors" and "integer overflow."



8. fmt: Format Output

(1) Common formatting verbs

Verb Meaning Applicable Types
%d Decimal integer int, int8/16/32/64
%f Floating-point number float32, float64
%s string string
%v Default format for any type Any type
%T Type Any type
%t Boolean bool
%q Quoted string string, rune
%x Hexadecimal int, []byte
%p Pointer Address pointer
%% Literal percent sign
GO
package main

import "fmt"

func main() {
    name := "Alice"
    age := 28
    height := 165.5
    isActive := true
    hobbies := []string{"coding", "reading", "hiking"}

    fmt.Printf("Name: %s\n", name)              // %s string
    fmt.Printf("Age: %d\n", age)                // %d integer
    fmt.Printf("Height: %.1f cm\n", height)     // %.1f float with 1 decimal
    fmt.Printf("Active: %t\n", isActive)        // %t boolean
    fmt.Printf("Hobbies: %v\n", hobbies)        // %v default format
    fmt.Printf("Name type: %T\n", name)         // %T type
    fmt.Printf("100%% complete!\n")             // %% literal %

    // %v Advanced usage: %+v displays the field name (struct), %#v displays Go syntax
    fmt.Printf("hobbies: %#v\n", hobbies)
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
Name: Alice
Age: 28
Height: 165.5 cm
Active: true
Hobbies: [coding reading hiking]
Name type: string
100% complete!
hobbies: []string{"coding", "reading", "hiking"}

(3) The Difference Between Print, Println, and Printf

Function Output Termination Use Cases
fmt.Print() No line break Continuous output
fmt.Println() Automatic line breaks + space-separated Simple debugging
fmt.Printf() Does not add a newline; requires \n Formatted output
fmt.Sprintf() Returns a string; does not print Concatenates strings


9. Complete Example: User Registration Form

Pull all the key concepts from this lesson together and write a user registration data collector:

GO
// main.go
package main

import (
    "fmt"
    "strconv"
)

// Defining User Role Enumerations Using Iota
const (
    RoleGuest     = iota // 0 Guest
    RoleUser             // 1 Regular User
    RoleAdmin            // 2 Admin
    RoleSuperAdmin       // 3 Super Admin
)

func main() {
    // 1. Use the := short declaration for user information
    name := "Alice"
    age := 28
    height := 165.5
    isActive := true
    role := RoleUser

    // 2. Explicit Type Conversion
    ageAsFloat := float64(age)
    heightAsString := strconv.FormatFloat(height, 'f', 1, 64)

    // 3. const Constants
    const MaxLoginAttempts = 5

    // 4. fmt: Formatted Output
    fmt.Println("========================================")
    fmt.Println("      User Registration Form")
    fmt.Println("========================================")
    fmt.Printf("Name:           %s\n", name)
    fmt.Printf("Age:            %d (%.0f years old)\n", age, ageAsFloat)
    fmt.Printf("Height:         %s cm\n", heightAsString)
    fmt.Printf("Active:         %t\n", isActive)
    fmt.Printf("Role:           %d (User)\n", role)
    fmt.Printf("Max Attempts:   %d\n", MaxLoginAttempts)
    fmt.Printf("Type Check:     name is %T, age is %T\n", name, age)
    fmt.Println("========================================")

    // 5. Demonstration of Zero Values for Variables
    var uninitializedAge int
    fmt.Printf("\nUninitialized age (zero value): %d\n", uninitializedAge)
}

Expected Output:

TEXT 📖 Display only
========================================
      User Registration Form
========================================
Name:           Alice
Age:            28 (28 years old)
Height:         165.5 cm
Active:         true
Role:           1 (User)
Max Attempts:   5
Type Check:     name is string, age is int
========================================

Uninitialized age (zero value): 0
🔥 Common Mistake: strconv.Atoi("abc") will return an error, which must not be ignored. Correct syntax: n, err := strconv.Atoi("abc"); if err != nil { ... }. Lesson 8 delves deeper into error handling.


❓ FAQ

Q Which is better, var or :=?
A We recommend using := inside functions—it's concise and enforces initialization; package-level variables must use var. The bytecode generated by both is exactly the same; it's just syntactic sugar.
Q The size of Go's int varies between 32-bit and 64-bit platforms. What issues might this cause?
A It is 8 bytes on 64-bit platforms and 4 bytes on 32-bit platforms. If you need to serialize your data (e.g., to JSON or a database), it is recommended to explicitly specify int32 or int64 to avoid cross-platform compatibility issues.
Q Go doesn't have an enum keyword. How do you create an enumeration?
A Use const + iota. Although it's not as strict as Java's enum class, it's sufficient. If you need type safety, you can use a custom type like type Role int along with a set of constants.
Q The value of iota starts at 0. Can it start at 1?
A Yes. Use _ = iota to skip 0, or iota + 1: const (A = iota + 1; B; C) results in A=1, B=2, C=3. This is commonly used in scenarios where values need to start at 1, such as HTTP status codes and months.
Q Why doesn't Go support implicit type conversion?
A The Go team believes that "explicit is better than implicit." Implicit conversions are the root cause of many bugs in Java and C++ (such as precision loss when mixing int and long operations). Go's strict type conversion makes code more readable and results in fewer bugs.
Q How do you convert between string and []byte?
A []byte(s) converts a string to a byte slice (copying the data); string(b) converts a byte slice to a string. These are commonly used in network I/O and encryption scenarios. Note: []byte is suitable for modification, while string is suitable for read-only use.
Q Can I use Chinese characters in variable names?
A Technically, yes (Go supports Unicode identifiers), but it is strongly discouraged. Chinese variable names make it difficult for international teams to collaborate on code, and some tools (such as linters and IDEs) may fail to recognize them. Always use English naming conventions (camelCase or underscores).
Q Can you take the address of a constant?
A No. Constants are defined at compile time and do not have a runtime memory address. &Pi will result in a compile-time error.

📖 Summary


📝 Exercises

  1. Basic Exercise (Difficulty ⭐): Declare 5 variables (name/age/height/isStudent/gpa) using both the var and := syntaxes, and print their values and types.

  2. Advanced Exercise (Difficulty ⭐⭐): Use iota to define four HTTP status code constants (200/404/500/503), and write a handleRequest(code int) function that returns the corresponding text (e.g., "OK," "Not Found," "Internal Server Error," or "Service Unavailable") based on the status code.

  3. Challenge Problem (Difficulty ⭐⭐⭐): Write a unit converter: Take a temperature in Fahrenheit as input and output the temperature in Celsius (formula: C = (F - 32) × 5/9). Requirements: (1) Use fmt.Scanf to read the input; (2) Use strconv.ParseFloat for type conversion; (3) Handle invalid input (return an error).

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏