# 4.4.4-3 基础类型

Go 语言内置的基础类型包括：

* 布尔类型
* 数字类型，例如整数、浮点数、复数等
* 字符串类型

编译器使用同一个结构来表示所有的基础类型，其定义如下：

```go
// A Basic represents a basic type.
type Basic struct {
    kind BasicKind
    info BasicInfo
    name string
}
```

`BasicInfo`用来描述类型属性，例如该类型是否是数字类型，是否可排序。其定义如下：

```go
type BasicInfo int

// Properties of basic types.
const (
    IsBoolean BasicInfo = 1 << iota
    IsInteger
    IsUnsigned
    IsFloat
    IsComplex
    IsString
    IsUntyped

    IsOrdered   = IsInteger | IsFloat | IsString
    IsNumeric   = IsInteger | IsFloat | IsComplex
    IsConstType = IsBoolean | IsNumeric | IsString
)
```

`BasicInfo`用来标识类型的性质，对应的常量申明已经解释了其潜在用途。

`BasicKind`用来标识实际类别，例如`Int32`, `Float64`等；这里简单罗列几个以做示例：

```go
// BasicKind describes the kind of basic type.
type BasicKind int

const (
    Invalid BasicKind = iota // type is invalid

    // predeclared types
    Bool
    // ... 省略其它类型
    Int8
    Complex128
    String
    UnsafePointer

    // types for untyped values
    UntypedBool
    UntypedInt
    UntypedRune
    UntypedFloat
    UntypedComplex
    UntypedString
    UntypedNil

    // aliases
    Byte = Uint8
    Rune = Int32
)
```

可以看出对于每一个基础类型，都有一个枚举类型与之对应，另外可以发现 go 中的`byte`与`rune`类型只是`uint8`与`int32`的类型别名。

这里稍稍多讲一下 Untypedxxx 这一组类型。go 的类型系统非常严格，如果一个表达式的类型是确定的，那么不管在什么场景下，编译器都不会做任何隐式的类型转换，例如如下代码：

```go
var a int16
var b int32

c := a + b // 错误信息：invalid operation: mismatched types int16 and int32
```

在赋值语句`c := a + b` 中，a与b的类型都是确定的整数类型，而将 a 转换为 int32 也是安全的，但 go 并不会这么做。反观 Java 则比较灵活，其定义了一组类型的隐式转换规则，例如如下 Java 代码是合法的：

```java
int a = 10;
float b = 1.0f;
String c = "Java";
String d = a + b + c; 
```

但是 go 也没有死板到无可救药，对于类型还不确定的表达式，go 会根据上下文来进行类型转换。但 go 中仅允许常量在声明时拥有不确定的类型，对应`BasicKind`中`Untypedxxx`的几类。

更准确地说，go 基础类型的字面量都是 untyped 的，例如 "golang", 12, 3.14 分别对应 UntypedString, UntypedInt, UntypedFloat. 当使用这些字面量进行操作，例如赋值、运算、作为参数传递时，编译器会根据上下文将其转换为目标类型。我们来看几个示例：

* 常量声明有类型

```java
const name string = "Golang"
```

"Golang" 类型为 UntypedString, 但是 name 的声明中指定类型为 string, 所以编译器在初始化 name 时会将 "Golang" 转换为 string 类型并且赋值给 name. 如果此时类型转换不匹配，则会报错：

```go
const name string = 1.2 // 错误信息：cannot convert 1.2(untyped float constant) to string
```

* 常量声明无类型

```go
const name = "Golang"
const alias string = name
```

name 没有申明类型，所以其类型复用字面量 "Golang" 的类型 UntypedString; 而 alias 的类型是 string, name 的值赋给 alias 的时候编译器会将其转换为 string 类型

* 根据常量 underlying type 进行转换

```go
type Str string

const name = "Golang"
const alias Str = name

const owner string = "google"
const ownerAlias Str = owner // 错误信息：cannot use owner (constant "google" of type string) as Str value in constant declaration
```

这里我们声明了新的类型 Str, 其 underlying type 是 string, 通过对 alias 的赋值语句可以看出：编译器依然可以将 UntypedString 转换为 Str 类型。但 owner 被显示声明成了 string 类型，其与 Str 毕竟是不同的类型，所以 ownerAlias 的赋值语句中，编译器不会将 string 类型的 owner 隐式转换为 Str 类型。

* 常量声明无类型

```go
type Str string

var name = "Golang"
var alias Str = name // 错误信息：cannot use name (variable of type string) as Str value in variable declaration
```

上面我们提到 go 仅仅支持常量拥有不确定类型，所以即使变量 name 没有申明类型，但编译器会根据右边的值推测出一个具体的类型赋给 name, 这里 "Golang" 的类型是 UntypedString。UntypedString 只能被转换为 string 类型，所以对 alias 的赋值会报错。

Untyped 类型的转换规则很简单：数字类型低精度可以向高精度转换，除此之外只有相同的类型才能相互转换。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gocompiler.shizhz.me/golang-bian-yi-qi-lei-xing-jian-cha/4.4.43-lei-xing-shu-ju-jie-gou-ji-chu-lei-xing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
