二 Go的基本语法

news2024/9/22 17:26:22

1. 基本类型

  • bool
  • string
  • int、int8、int16、int32、int64
  • uint、uint8、uint16、uint32、uint64、uintptr
  • byte // uint8 的别名
  • rune // int32 的别名 代表一个 Unicode 码
  • float32、float64
  • complex64、complex128

2. 三种声明变量

2.1 标准格式

var name type

其中,var 是声明变量的关键字,name 是变量名,type 是变量的类型

2.2 批量格式

var (
    a int
    b string
    c []float32
    d func() bool
    e struct {
        x int
    }
) 

2.3 简短格式

名字 := 表达式
i, j := 0, 1
需要注意的是,简短模式(short variable declaration)有以下限制:
定义变量,同时显式初始化。 //相当于赋值,可以不用再声明获取到的变量的类型
不能提供数据类型。 // 因为赋值直接会有类型了,所以不用提供数据类型
只能用在函数内部。 //全局定义还是得用var

示例:

func main() {
   x:=100
   a,s:=1, "abc"
}

3. 变量初始化

3.1 标准格式

var 变量名 类型 = 表达式
var hp int = 100

上面代码中,100 和 int 同为 int 类型,int 可以认为是冗余信息,因此可以进一步简化初始化的写法

3.2 编译器推导类型的格式

var defence = 
var damageRate float32 = 0.17
var damage = float32(attack-defence) * damageRate
fmt.Println(damage)

代码说明:

  • 第 1 和 2 行,右值为整型,attack 和 defence 变量的类型为 int。
  • 第 3 行,表达式的右值中使用了 0.17。由于Go语言和C语言一样,编译器会尽量提高精确度,以避免计算中的精度损失。所以这里如果不指定 damageRate 变量的类型,Go语言编译器会将 damageRate 类型推导为 float64,我们这里不需要 float64 的精度,所以需要强制指定类型为 float32。
  • 第 4 行,将 attack 和 defence 相减后的数值结果依然为整型,使用 float32() 将结果转换为 float32 类型,再与 float32 类型的 damageRate 相乘后,damage 类型也是 float32 类型

3.3 短变量声明并初始化

如果 hp 已经被声明过,但依然使用:=时编译器会报错
// 声明 hp 变量
var hp int
// 再次声明并赋值
hp := 10

示例:

conn, err := net.Dial(“tcp”,“127.0.0.1:8080”) net.Dial
提供按指定协议和地址发起网络连接,这个函数有两个返回值,一个是连接对象(conn),一个是错误对象(err)

4. 多变量同时赋值

var b = 200
b, a = a, b
fmt.Println(a, b)

5. 变量作用域

5.1 局部变量

import (
    "fmt"
)
func main() {
    //声明局部变量 a 和 b 并赋值
    var a int = 3
    var b int = 4
    //声明局部变量 c 并计算 a 和 b 的和
    c := a + b
    fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}

5.2 全局变量

import "fmt"
//声明全局变量
var c int
func main() {
    //声明局部变量
    var a, b int
    //初始化参数
    a = 3
    b = 4
    c = a + b
    fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}

5.3 形式参数

import (
    "fmt"
)
//全局变量 a
var a int = 13
func main() {
    //局部变量 a 和 b
    var a int = 3
    var b int = 4
    fmt.Printf("main() 函数中 a = %d\n", a)
    fmt.Printf("main() 函数中 b = %d\n", b)
    c := sum(a, b)
    fmt.Printf("main() 函数中 c = %d\n", c)
}
func sum(a, b int) int {
    fmt.Printf("sum() 函数中 a = %d\n", a)
    fmt.Printf("sum() 函数中 b = %d\n", b)
    num := a + b
    return num
}

6. 格式化输出

import (
    "fmt"
    "math"
)
func main() {
    fmt.Printf("%f\n", math.Pi)
    fmt.Printf("%.2f\n", math.Pi)
}

通用占位符:

  • %v 默认使用,可通用
  • %T输出类型
  • %%输出百分号

布尔型:

  • %t

宽度标识符具体见下图:

n := 12.34
fmt.Printf("%f\n", n)
fmt.Printf("%9f\n", n)
fmt.Printf("%.2f\n", n)
fmt.Printf("%9.2f\n", n)
fmt.Printf("%9.f\n", n)

输出:
12.340000
12.340000
12.34
    12.34
       12

7. 整形、浮点、布尔值结合

package main
import "fmt"
func main() {
   i := 0
   var c float32 = 0.2
   b := float32(sum(3, 4))
   if b > 7 {
      i = 1
   }
   fmt.Printf("当前c的值为:%.2f\n", c)
   fmt.Printf("当前i的值为:%d\n", i)
   b2 := isBool(2)
   fmt.Printf("b2的值为: %t\n", b2)
}
func sum(a, b int) int {
   return a + b
}
func isBool(i int) bool { return i != 0 }

8. 字符串

8.1 常用符号

\n:换行符
\r:回车符
\t:tab 键
\u 或 \U:Unicode 字符
\:反斜杠自身

8.2 定义多行字符串

使用 `符号来定义
内部字符串以原始文字输出,转义符号失效

package main
import "fmt"
func main() {
   const str1 = `第一行
第二行
第三行
\r\n
`
   fmt.Printf("str1:%v", str1)
}

8.3 字符串方法

8.3.1 字符串长度

  1. 以字节长度计算
package main
import "fmt"
func main() {
   tip1 := "gen ji is a ninja"
   fmt.Println(len(tip1))
   tip2 := "忍者"
   fmt.Println(len(tip2))
}

输出:
17  // 纯英文与空格只占用一个长度
6  //一个汉字占用三个长度
  1. 按照字符个数计算(计算UTF8中的字符个数,需要用到RuneCountInString() 函数)
package main
import (
   "fmt"
   "unicode/utf8"
)
func main() {
   fmt.Println(utf8.RuneCountInString("龙龟冲!"))
   fmt.Println(utf8.RuneCountInString("龙龟, Fight!"))
}

8.4 获取字符串元素

ASCii码输出

theme := "狙击 start"
for i := 0; i < len(theme); i++ {
    fmt.Printf("ascii: %c  %d\n", theme[i], theme[i])
}

Unicode编码输出

package main
import "fmt"
func main() {
   theme := "狙击 start"
   for i, s := range theme {
      fmt.Printf("%d Ascii: %c %d\n", i, s, s)
   }
}

输出:
0 Ascii:29401
3 Ascii:20987
6 Ascii:   32
7 Ascii: s 115
8 Ascii: t 116
9 Ascii: a 97
10 Ascii: r 114
11 Ascii: t 116

8.5 字符串值获取

tracer := "死神来了, 死神bye bye"
comma := strings.Index(tracer, ", ")
pos := strings.Index(tracer[comma:], "死神")  //等价于从", 死神bye bye"字符串开始查找
fmt.Println(comma, pos, tracer[comma+pos:])

输出:
12 3 死神bye bye

8.6 字符串的拼接

package main
import (
   "bytes"
   "fmt"
)
func main() {
   a := "今天"
   b := "不错"
   var stringBuffer bytes.Buffer
   stringBuffer.WriteString(a)
   stringBuffer.WriteString(b) //这种拼接方式比+号高效
   fmt.Println(stringBuffer.String())
}

9. 类型转换

精度丢失问题

package main
import (
   "fmt"
   "math"
)
func main() {
   // 输出各数值范围
   fmt.Println("int8 range:", math.MinInt8, math.MaxInt8)
   fmt.Println("int16 range:", math.MinInt16, math.MaxInt16)
   fmt.Println("int32 range:", math.MinInt32, math.MaxInt32)
   fmt.Println("int64 range:", math.MinInt64, math.MaxInt64)
   // 初始化一个32位整型值
   var a int32 = 1047483647
   // 输出变量的十六进制形式和十进制值
   fmt.Printf("int32: 0x%x %d\n", a, a)
   // 将a变量数值转换为十六进制, 发生数值截断
   b := int16(a)
   // 输出变量的十六进制形式和十进制值
   fmt.Printf("int16: 0x%x %d\n", b, b)
   // 将常量保存为float32类型
   var c float32 = math.Pi
   // 转换为int类型, 浮点发生精度丢失
   fmt.Println(int(c))
}

10. 指针

10.1 指针取值

当使用&操作符对普通变量进行取地址操作并得到变量的指针后,可以对指针使用*操作符,也就是指针取值,代码如下

package main
import (
    "fmt"
)
func main() {
    // 准备一个字符串类型
    var house = "Malibu Point 10880, 90265"
    // 对字符串取地址, ptr类型为*string
    ptr := &house
    // 打印ptr的类型
    fmt.Printf("ptr type: %T\n", ptr)
    // 打印ptr的指针地址
    fmt.Printf("address: %p\n", ptr)
    // 对指针进行取值操作
    value := *ptr
    // 取值后的类型
    fmt.Printf("value type: %T\n", value)
    // 指针取值后就是指向变量的值
    fmt.Printf("value: %s\n", value)
}

取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值

package main
import "fmt"
func swap(a, b *int) {
   fmt.Println(a)
   fmt.Println(b)
   *b, *a = *a, *b
}
func main() {
   x, y := 1, 2
   swap(&x, &y)
   fmt.Println(x, y)
}

输出:
21
package main
import "fmt"
func swap(a, b *int) {
    b, a = a, b
}
func main() {
    x, y := 1, 2
    swap(&x, &y)
    fmt.Println(x, y)
}

输出12

10.2 接收启动参数

Go语言内置的 flag 包实现了对命令行参数的解析,flag 包使得开发命令行工具更为简单
下面的代码通过提前定义一些命令行指令和对应的变量,并在运行时输入对应的参数,经过 flag 包的解析后即可获取命令行的数据

package main
// 导入系统包
import (
   "flag"
   "fmt"
)
// 定义命令行参数
var mode = flag.String("mode", "", "process mode")
func main() {
   // 解析命令行参数
   fmt.Printf("%T\n", mode)
   flag.Parse()
   // 输出命令行参数
   fmt.Println(*mode)
}

将这段代码命名为 main.go,然后使用如下命令行运行: go run main.go --mode=fast 命令行输出结果如下:
fast

代码说明如下:
flag定义的都是指针类型的变量
第 10 行,通过 flag.String,定义一个 mode 变量,这个变量的类型是 *string。后面 3 个参数分别如下:
参数名称:在命令行输入参数时,使用这个名称。
参数值的默认值:与 flag 所使用的函数创建变量类型对应,String 对应字符串、Int 对应整型、Bool 对应布尔型等。
参数说明:使用 -help 时,会出现在说明中。
第 15 行,解析命令行参数,并将结果写入到变量 mode 中。
第 18 行,打印 mode 指针所指向的变量。

在这里插入图片描述

10.3 创建指针方法

new(类型)

package main
import "fmt"
func main() {
   a := new(string)
   fmt.Printf("%T\n", a)  //创建了一个指针类型
   *a = "今天天气不错"
   fmt.Println(*a)
}

输出:
*string
今天天气不错

11. Go变量的生命周期

11.1 变量种类

全局变量:它的生命周期和整个程序的运行周期是一致的;
局部变量:它的生命周期则是动态的,从创建这个变量的声明语句开始,到这个变量不再被引用为止;
形式参数和函数返回值:它们都属于局部变量,在函数被调用的时候创建,函数调用结束后被销毁。

堆(heap):堆是用于存放进程执行中被动态分配的内存段。它的大小并不固定,可动态扩张或缩减。当进程调用 malloc 等函数分配内存时,新分配的内存就被动态加入到堆上(堆被扩张)。当利用 free 等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减);

栈(stack):栈又称堆栈, 用来存放程序暂时创建的局部变量,也就是我们函数的大括号{ }中定义的局部变量。

11.2 变量逃逸

var global *int
func f() {
    var x int
    x = 1
    global = &x
}
func g() {
    y := new(int)
    *y = 1
}
  • 上述代码中,函数 f 里的变量 x 必须在堆上分配,因为它在函数退出后依然可以通过包一级的 global
    变量找到,虽然它是在函数内部定义的。用Go语言的术语说,这个局部变量 x 从函数 f 中逃逸了。
  • 相反,当函数 g 返回时,变量 *y 不再被使用,也就是说可以马上被回收的。因此,*y 并没有从函数 g 中逃逸,编译器可以选择在栈上分配
    *y 的存储空间,也可以选择在堆上分配,然后由Go语言的 GC(垃圾回收机制)回收这个变量的内存空间。
  • 简而言之就是f函数中的x变量虽然是在局部被定义的,但是因为他的值以指针的形式被另一个变量接收了,所以在外部全局中其实可以使用到他的指针地址,所以在Go术语中这种现象称之为逃逸
  • 然而在g函数中,并没有外部变量去接收y的指针地址,所以当函数结束时就可以把变量的内存空间通过GC加以回收
  • 在实际的开发中,并不需要刻意的实现变量的逃逸行为,因为逃逸的变量需要额外分配内存,同时对性能的优化可能会产生细微的影响

12. 常量

Go语言中的常量使用关键字 const
定义,用于存储不会改变的数据,常量是在编译时被创建的,即使定义在函数内部也是如此,并且只能是布尔型、数字型(整数型、浮点型和复数)和字符串型。由于编译时的限制,定义常量的表达式必须为能被编译器求值的常量表达式

在Go语言中,你可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。

  • 显式类型定义: const b string = “abc”
  • 隐式类型定义: const b = “abc”

常量的值必须是能够在编译时就能够确定的,可以在其赋值表达式中涉及计算过程,但是所有用于计算的值必须在编译期间就能获得。

  • 正确的做法:const c1 = 2/3
  • 错误的做法:const c2 = getNumber() // 引发构建错误: getNumber() 用做值

如果是批量声明的常量,除了第一个外其它的常量右边的初始化表达式都可以省略,如果省略初始化表达式则表示使用前面常量的初始化表达式,对应的常量类型也是一样的。例如:

const (
    a = 1
    b
    c = 2
    d
)
fmt.Println(a, b, c, d) // "1 1 2 2"

常量生成器

常量声明可以使用 iota 常量生成器初始化,它用于生成一组以相似规则初始化的常量

package main
import "fmt"
func main() {
   type Weekday int
   const (
      Sunday Weekday = iota
      Monday
      Tuesday
      Wednesday
      Thursday
      Friday
      Saturday
   )
   fmt.Println(Sunday)
   fmt.Println(Monday)
   fmt.Println(Tuesday)
   fmt.Println(Wednesday)
   fmt.Println(Thursday)
   fmt.Println(Friday)
   fmt.Println(Saturday)
}

输出:
0
1
2
3
4
5
6

13. 关键字与标识符

Go语言的词法元素包括 5
种,分别是标识符(identifier)、关键字(keyword)、操作符(operator)、分隔符(delimiter)、字面量(literal),它们是组成Go语言代码和程序的最基本单位。

13.1 关键字

breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar

PS:坑爹的表格真难用,该优化了啊!

13.2 标识符

标识符是指Go语言对各种变量、方法、函数等命名时使用的字符序列,标识符由若干个字母、下划线_、和数字组成,且第一个字符必须是字母

标识符的命名需要遵守以下规则:

  • 由 26 个英文字母、0~9、_组成;
  • 不能以数字开头,例如 var 1num int 是错误的;
  • Go语言中严格区分大小写;
  • 标识符不能包含空格;
  • 不能以系统保留关键字作为标识符,比如 break,if 等等。

命名标识符时还需要注意以下几点:

  • 标识符的命名要尽量采取简短且有意义;
  • 不能和标准库中的包名重复;
  • 为变量、函数、常量命名时采用驼峰命名法,例如 stuName、getVal;

在Go语言中还存在着一些特殊的标识符,叫做预定义标识符,如下表所示:
在这里插入图片描述

预定义标识符一共有 36 个,主要包含Go语言中的基础数据类型和内置函数,这些预定义标识符也不可以当做标识符来使用。

14 运算符优先级

Go语言运算符优先级和结合性一览表**
在这里插入图片描述

15. Go的字符串与数值类型的转换**

package main
import (
   "fmt"
   "strconv"
)
func main() {
   value1, err1 := strconv.Atoi("哈哈") // Ascii To Int
   fmt.Println(value1)
   fmt.Println(err1)
   var x = 4
   value2 := strconv.Itoa(x) // 数字转字符串是不会出err
   fmt.Println(value2)

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/401099.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MyBatis-Plus联表查询的短板,该如何解决呢

mybatis-plus作为mybatis的增强工具&#xff0c;它的出现极大的简化了开发中的数据库操作&#xff0c;但是长久以来&#xff0c;它的联表查询能力一直被大家所诟病。一旦遇到left join或right join的左右连接&#xff0c;你还是得老老实实的打开xml文件&#xff0c;手写上一大段…

链表及其基本操作

1.单链表&#xff1a;1.1定义/性质&#xff1a;链表是线性表的链式存储方式。单链表通过指针线性遍历&#xff0c;删除/增加节点时间复杂度为O(1&#xff09;,访问节点时间复杂度为O(n)。单链表分为带头结点和不带头结点两种&#xff0c;带头结点是为了方便统一操作&#xff08…

数据结构:链式二叉树初阶

目录 一.链式二叉树的逻辑结构 1.链式二叉树的结点结构体定义 2.链式二叉树逻辑结构 二.链式二叉树的遍历算法 1.前序遍历 2.中序遍历 3.后序遍历 4.层序遍历(二叉树非递归遍历算法) 层序遍历概念: 层序遍历算法实现思路: 层序遍历代码实现: 三.链式二叉树遍历算…

蓝桥杯三月刷题 第六天

文章目录&#x1f4a5;前言&#x1f609;解题报告&#x1f4a5;星期计算&#x1f914;一、思路:&#x1f60e;二、代码&#xff1a;&#x1f4a5;考勤刷卡&#x1f914;一、思路:&#x1f60e;二、代码&#xff1a;&#x1f4a5;卡片&#x1f914;一、思路:&#x1f60e;二、代…

Spring SpringBoot中使用Mybatis-plusDemo1

官网:https://baomidou.com GitHub:GitHub - baomidou/mybatis-plus: An powerful enhanced toolkit of MyBatis for simplify development Gitee:mybatis-plus: mybatis 增强工具包&#xff0c;简化 CRUD 操作。 文档 http://baomidou.com低代码组件库 http://aizuda.com My…

Leetcode.剑指 Offer II 023. 两个链表的第一个重合节点

题目链接 Leetcode.剑指 Offer II 023. 两个链表的第一个重合节点 easy 题目描述 给定两个单链表的头节点 headA和 headB&#xff0c;请找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null。 注意&#xff0c;函数返回结果后&#xff0c;链表必…

Lumion 2023即将上线,低配电脑如何驾驭Lumion

年更选手Lumion的更新速度“从不让人失望”&#xff0c;自从Lumion 12更新完之后&#xff0c;官方意料之中的没了动静。但是就在这几天&#xff0c;官方终于放出了首支Lumion 2023的更新预告&#xff0c;并且宣布将于本月中旬发布&#xff01;Lumion 2023主要变化是支持光线追踪…

【Linux:环境变量的理解】

目录 1 Z(zombie)-僵尸进程 2 孤儿进程 3 环境变量 3.1 基本概念 3.2 测试HOME 3.3 和环境变量相关的命令 3.4 环境变量的组织方式 3.5 环境变量通常是具有全局属性的 在讲环境变量之前&#xff0c;我们先把上次遗留知识点给总结了&#xff08;僵尸进程和孤儿进程&…

fast-api 一款快速将spring的bean发布成接口并生产对应swagger文档调试的轻量级工具

fast-api简介背景开发痛点:分析需求实战fast-api快速上手1. 引入依赖2. FastApiMapping标记service对象3. swagger2/knife4j 在线测试进阶使用开启调试模式支持指定类或包目录发布如何关闭fast-api自定义fast-api的前缀写在最后简介 fast-api 一款快速将spring的bean(service)发…

案例学习6-没有复用思想

背景&#xff1a; 上述两个方法查询同一张表&#xff0c;只是数据结构不同&#xff0c;完全可以合成一份方法&#xff0c;减少代码冗余。 实现效果如下 不传参&#xff0c;查询所有的数据 传入特定参数实现按条件查询&#xff1a; 实现方式&#xff1a; GetMapping(value &q…

Antlr Tool与antlr runtime的版本一致性问题

1. 意外的问题 在学习Antlr4的visitor模式时&#xff0c;使用IDEA的Antlr插件完成了Hello.g4文件的编译&#xff0c;指定的package为com.sunrise.hello 使用visitor模式遍历语法解析树&#xff0c;遍历过程中打印hello语句 public class HelloVisitorImpl extends HelloBaseVi…

Linux进程和任务管理和分析和排查系统故障

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有收获&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️夕阳下&#xff0c;是最美的绽放&#xff0…

基于遥感解译与GIS技术生态环境影响评价图件制作

《环境影响评价技术导则 生态影响》&#xff08;HJ 19—2022&#xff09;即将实施&#xff0c;其中生态影响评价图件是生态影响评价报告的必要组成内容&#xff0c;是评价的主要依据和成果的重要表现形式&#xff0c;是指导生态保护措施设计的重要依据。在众多图件中&#xff…

java八股文--java基础

java基础1.什么是面向对象&#xff0c;谈谈对面向对象的理解2.JDK JRE JVM的区别与联系3.和equals4.hashCode与equals5.String StringBuffer StringBuilder的区别6.重载和重写的区别7.接口和抽象类8.List和Set的区别9.ArrayList和LinkedList10.HashMap和HashTable的区别&#x…

详解命令模式本质及其在高复杂调用中的实践案例

作者&#xff1a;范灿华 阿里同城履约物流技术团队 命令模式是一种设计模式&#xff0c;总结了在特定场景下的最佳设计实践。本文将为大家介绍命令模式的模式本质及灵活运用&#xff0c;并通过一个真实的电商履约系统中的库存调用需求为案例&#xff0c;分享其在高复杂调用中的…

【C语言】8道经典指针笔试题(深度解剖)

上一篇我们也介绍了指针的笔试题&#xff0c;这一篇我们趁热打铁继续讲解8道指针更有趣的笔试题&#xff0c;&#xff0c;让大家更加深刻了解指针&#xff0c;从而也拿下【C语言】指针这个难点! 本次解析是在x86&#xff08;32位&#xff09;平台下进行 文章目录所需储备知识笔…

3分钟上手,2小时起飞!教你玩转OceanBase Cloud

盼星星盼月亮&#xff01;掰掰手指&#xff0c;距离 3 月 25 日还有 123456......两周啦&#x1f929;~ 除了白天的主论坛和分论坛的精彩分享外&#xff0c;晚间的 3 场 Hands-on Workshop 动手实验营也深得大家期待&#xff0c;从部署到迁移&#xff0c;从 On-Premise 到 Clou…

OpenAI——CLIPs(代码使用示例)

OpenAI——CLIPs(打通NLP与CV) Open AI在2021年1月份发布Contrastive Language-Image Pre-training(CLIP),基于对比文本-图像对对比学习的多模态模型&#xff0c;通过图像和它对应的文本描述对比学习&#xff0c;模型能够学习到文本-图像对的匹配关系。它开源、多模态、zero-s…

【Three.js】shader特效 能量盾

shader特效之能量盾前言效果噪点图主要代码index.htmldepth-fs.jsdepth-vs.jsshield-fs.jsshield-vs.js相关项目前言 效果噪点图 为了可以自定义能量球的效果&#xff0c;这里使用外部加载来的噪点图做纹理&#xff0c;省去用代码写特效的过程。 主要代码 index.html <…

数据表(一) - 数据表的种类

在游戏项目中缺少不了数据表&#xff0c;数据决定了游戏的整个进程&#xff0c;因此怎么用数据表配置数&#xff0c;配置数据时是否方便成了关键的问题。那么如何来理解数据表的存在呢&#xff1f;数据表完全可以认为是一个本地的数据库&#xff0c;只不过这个数据库里的数据是…