Go 语言入门指南:基础语法和常用特性解析

news2024/11/18 3:35:35

文章目录

  • Hello,World
  • 变量、指针及赋值
    • 变量和常量
    • 指针
    • 赋值
  • 选择和循环
    • 选择
    • 循环
  • 基本数据类型
    • 整型
      • 整型的取值范围
    • 运算符
      • 二元运算符
      • 一元运算符
    • 浮点型
    • 复数和布尔类型
  • 字符串
    • rune
    • Unicode和UTF-8
    • 按字节访问
    • 按字符rune访问
    • 特点
  • 数组
    • 数组的定义
      • 1. 使用默认初始值
      • 2. 定义并初始化
      • 3. 省略数组长度
      • 4. 索引赋值初始化
    • 数组特点
    • 数组是默认按值传递
  • slice
    • 原型
    • 基本操作
    • append
    • slice的增长过程
    • copy
    • 其他
  • map
    • 基本操作
    • 特点
  • struct
  • 参考

Hello,World

package main

import "fmt"

func main(){
    fmt.Println("Hwllo,World!")
}
  • 1 1 1行是包的声明。本例中是main包,main包是每个项目的入口。
  • 3 3 3行,使用g键字import导入Go语言提供的标准包fmt。
  • 5 5 5行定义了一个函数,func是定义函数的关键字。
  • 6 6 6行使用fmt的Println函数输出字符串Hello,World!

注意:Go语言每行代码行尾是不需要加分号; 的,编译器会把换行符解析成分号,不能把函数的左扩号单独成行。

变量、指针及赋值

变量和常量

  • 变量声明使用var关键字
  • 常量声明使用const关键字
  • 变量的定义形式: var name 【类型】 = 【表达式】

注意:使用过程中,"类型"和"表达式"可以省略一个,但不能同时省略。Go语言能进行自动推导,根据类型推默认表达式,也能根据表达式推出类型。

类型默认值

  • 数字类型默认为0
  • 布尔类型默认为false
  • 字符串类型默认为""
  • 接口、slice、指针、map、通道、函数等类型默认值为nil

变量定义示例

// 省略类型
var m = 2

// 省略表达式
var n int

// 多个变量一起声明
var a, b, c int

// 多个变量一同通过表达式声明
var i, j, k = 1, "hello", true

常量定义示例

  • 常量的值是在程序编译的时候确定的,之后不可改变。
const LEN = 10

// 一次定义多个常量
const (
	SYS = "Windows"
	Type = "string"
)

:==

n1 := 10    // 正确   
n2 = 10     // 错误

var n3 int
n3 = 10     // 正确
  • := 是声明并赋值
  • =是给声明后的变量赋值

指针

  • Go语言支持指针,指针的默认初始值为nil

    var int x  
    p := &x    // & 为取地址符号。 p为指向x的整型指针
    *p = 1		
    fmt.Println(x)
    
  • Go也支持new函数

p := new(int)

赋值

  • =为赋值符号。等号左边是变量名,等号右边是表达式。

  • Go语言也提供了自增、自减和*=+=等先运算后赋值的操作

    m := 1
    m++    	// 相当于 m = m + 1
    m -= 1  // 相当于 m = m - 1
    
  • Go同样支持多重赋值

    m := 2
    n := 3
    m,n = n,m  // 实现交换m,n的值
    
    var a, b, c int // a, b, c 同时声明 
    a,b,c = 1,2,3  	// a,b, c 同时赋值
    

选择和循环

选择

  • Go语言也提供if elseswitch语句

  • switch语句的每个case不需要额外的break

    if expression == true {
        fmt.Println("条件成立1")
    }
    
    if expression == false {
        fmt.Println("条件成立2")
    }
    

循环

  • Go语言只提供for关键字,没有while等其他关键字。

for形式

// 一般形式
for i := 0; i < 100; i++ {
    
}

// 相当于 while
for {
    
}

// 相当于 do ... while
for ok := true; ok; ok = expression{
    
}

// for循环也支持range函数 
arr := []int{1, 2, 3, 4}    // 定义切片slice,类似c的数组
for i, v : range arr{
    fmt.Println("index: ",i, "value: ", v)
}

基本数据类型

整型

  • int8int8int6int32分别对应8、16、32、64位整数。

整型的取值范围

  • 整型分带符号整数和无符号整数。int为带符号整型,uint为无符号类型。

    // 带符号整数
    int8  (-128 ~ 127)
    int16 (-32768 ~ 32767)
    int32 (-2,147,483,648 ~ 2,147,483,647)
    int64 (-9,233,372,036,854,775,808 ~ 9,233,372,036,854,775,807)
    
    // 无符号整数
    unit8  (0 ~ 255)
    unit16 (0 ~ 65,535)
    unit32 (0 ~ 4,294,967,295)
    unit64 (0 ~ 18,446,744,073,709,551,615)
    

运算符

二元运算符

  • 二元运算符包括算术运算、逻辑运算和比较运算

运算符优先级从上到下的递减顺序排列:

*	/	%	<< 	>>	&	&^
+	-	|	^
==	!=	<	<=	>	>=
&&
||
  • 同一优先级,使用左优先结合规则。

一元运算符

  • 一元运算符包括正负号、bit位运算

    &	与 AND
    |	或 OR
    ^	异或 XOR
    &^ 	位清空 (AND NOT)
    << 	左移
    >> 右移
    
  • 左移<<:左移运算用零填充右边空缺的bit位

  • 右移>>:无符号数右移运算用0填充左边空缺的bit位,有符号数的右移运算用符号位的值填充左边空缺的bit位。

浮点型

  • 浮点型分float32float64。推荐使用float64

  • float32表示小数可能会出现精度丢失。下面给出示例。

    package main
    
    import "fmt"
    
    func main() {
       	var f1 float32 = 9.90
    	fmt.Println(f1*100)
    	
    	var f2 float64 = 9.90
    	fmt.Println(f2*100)
    }
    
    /* output
    989.99994
    990
    */
    

复数和布尔类型

复数类型

  • 复数分为complex64complex128,它们分别有float32float64组成。

  • 复数由实部和虚部组成,内置的realimag函数用于获取复数的实部和虚部

    var a complex128 = complex(2,3) // 2+3i
    fmt.Println(real(a)) // 2
    fmt.Println(imag(a)) // 3
    

布尔类型

  • bool的值用true和false表示

  • Go语言的布尔类型没有强制类型转换,无法把0转换成false

    var b bool
    b = 0	// 报错
    

字符串

  • Go语言字符串按字节存储,不同字符占用不同数目的字节。

  • 字符串的字符按unicode编码存储,不同的字符按1~4个字节存储。其中,中文汉字占用3个字节,英文占用1个字节。

  • 字符串索引访问是按字节访问的,而不是字符。

img

rune

  • unicode通常用4个字节来表示,对应Go语言的字符rune占4个字节

  • rune类型是一个衍生类型,在内存里面使用int32类型的4各字节存储

    type rune int32
    

Unicode和UTF-8

  • Unicode支持超过一百种的语言和十万字符的码点。

  • UTF-8是Unicode标准的一种实现。

  • UTF-8特点:

    • 字符长度可变,长度1到4字节不等。
    • 第一个bit为0,那么长度为1字节,使用剩余7位存放字符,正好能覆盖ASCII码字符集。
    • 前两位是10,则表示长度为两个字节,第二个字节以0开头。
    • 对于三个字节的UTF-8码。这三个字节分别是110、10和0。

按字节访问

package main

import "fmt"

func main() {
	var s = "嘻哈china"
	for i:=0;i<len(s);i++ {
		fmt.Printf("%d %x ", i, s[i])
	}
 
}

-----------
0 e5 1 98 2 bb 3 e5 4 93 5 88 6 63 7 68 8 69 9 6e 10 61

按字符rune访问

package main

import "fmt"

func main() {
	var s = "嘻哈china"
	for codepoint, runeValue := range s {
		fmt.Printf("%d %d ", codepoint, int32(runeValue))
	}
}

-----------
0 22075 3 21704 6 99 7 104 8 105 9 110 10 97

对字符串进行range遍历,每次迭代出两个变量codepoint和runeValue。

codepoint表示字符起始位置,runeValue表示对于的unicode编码(类型是rune)

特点

  • 字符串是只读的,不支持按索引修改。
  • 字符串支持切片成子串

字节数组和字符串的转换

借助[]byte()string()即可

var s1 = "hello world"     
var b = []byte(s1)     // 字符串转字节数组
var s2 = string(b)	   // 字节数组转字符串

/*
b = [104 101 108 108 111 32 119 111 114 108 100]
s2 = hello world
*/

数组

  • 在Go语言中,数组的使用频率并不高,因为数组长度不可变,很多时候都是使用slice(切片)。slice比数组更灵活,长度是可变的。

数组的定义

1. 使用默认初始值

var a [3]int
  • 定义了长度为3的整型数组,三个元素都是默认初始值0

2. 定义并初始化

var b [3]int = [3]int{1, 2, 3}
var b = [3]int{1, 2, 3}

3. 省略数组长度

c := [...]int{1, 2, 3}
  • 数组长度由后面元素的个数决定。这里数组的长度为3

4. 索引赋值初始化

d := [...]int{4, 4:1, 1:2}

// d : {4, 2, 0, 0, 1}
  • 并没有给所有的元素赋值,而且赋值使用了index:value的方式。4:1的意思是给下标为4的元素赋值为1,。
  • 数组长度根据最大下标确定。

数组特点

  • [3]int[4]int是两种不同的数据类型,这两种不同的数组在编译时就已经确定。把[4]int类型的变量赋值给[3]int类型的变量会报错。
  • Go语言数组长度是数组的一部分,并非向C语言那样只存储数组的地址
  • 在分配内存底层空间时,数组的元素是紧挨着分配到固定位置的,这也是数组长度不可变的原因。

数组是默认按值传递

  • Go语言数组是传递值的,不同于其他语言的数组都是传递引用的。
  • 值传递涉及数组的拷贝,会浪费性能,但形参数组的修改不会影响原数组。

给出一个实例,修改数组的0索引位置的元素

一种是直接传数组,此时是值传递。另一种是传数组地址,此时是引用传递(指针)。

package main

import "fmt"

func main() {
	var a [3]int = [3]int{1, 2, 3}
    
	change_arr_by_value(a)
	fmt.Println(a[0]) // 1 按值传递,修改失败

	change_arr_by_reference(&a)
	fmt.Println(a[0]) // 999 按索引传递,修改成功
}

func change_arr_by_value(arr [3]int) {
	arr[0] = 999
}

func change_arr_by_reference(arr *[3]int) {
	arr[0] = 999
}

slice

  • slice(切片)是一个拥有相同类型元素的可变长序列,且slice定义和数组的定义很像。

原型

type SliceHeader struct {
	Data uintptr	// 指针
	Len int			// 长度
	Cap int			// 容量
}

说明

  • 指针指向slice开始访问的第一个元素
  • 长度是切片的长度,及元素个数
  • 容量是切片能访问的最大元素个数。slice的容量大于等于silice的长度

切片的底层是数组,Go语言的切片对应着底层数组。一个底层数组可以对应多个slice。

基本操作

定义

s := []int{1, 2, 3, 4, 5}

如果在方括号中指定了长度或写入省略号,那就是一个数组。

ss := make([]int, 10)

make函数定义了[ ]int类型的切片,长度为10,元素默认值为0

释放slice

ss = nil

如果将slice赋值为nil,垃圾回收机制将会回收slice的空间。

获取长度和容量

len(slice)
cap(slice)

切片

  • 切片s[i:j]是左闭右开,索引区间是[i, j)
s := []int{0, 1, 2, 3, 4, 5}
s[0:3] // {0, 1, 2}
  • 左边界i不写,默认是0。右边界j不写,默认是切片的容量cap(slice)。
  • s[:]是整个切片。

数组的切片

  • 对数组切片的修改会影响原数组。
a := [...]int{1, 2, 3, 4, 5}
ss := a[1:3]
ss[0] = 99
ss[1] = -99

fmt.Println(ss)  // [99, -99]
fmt.Println(a) 	 // [1, 99, -99, 4, 5]

slice默认是引用传递

append

  • slice的长度是动态的。append可以在原来的切片上插入元素,可以在开头、结尾、指定位置插入元素或其他slice。数组不能直接插入,要转换成切片才能添加。
s = []int{1, 2, 3}			// 定义切片
arr = [3]int{66, 77, 88}	// 定义数组

头插

ss = append(a[:], ss...)
ss = append([]int{1}, ss...)

注意:ss...意思是把切片ss,拆解成一个个元素。之后将依次插入。 a[:]是取数组的切片。

尾插

ss = append(ss, 1)
ss = append(ss, a[:]...)

任意位置插入

  • 演示在ss的索引为1的位置插入
ss = append(ss[:1], append(a[:], ss[1:]...)...)

slice的增长过程

切片的底层是数组,如果使用append函数向切片中添加元素是,实际上是把元素放到切片的底层数组。

如果底层数组满了,没有空间,这时再向切片添加元素,Go只能创建一个更大的新数组,将原来的数组复制到新数组,并把新数组作为切片的底层数组。

代码演示

s1 := []int{1, 2, 3}
fmt.Printf("长度:%d,容量:%d,数组地址:%p\n", len(s1), cap(s1), s1)
s1 = append(s1, 4)
fmt.Printf("长度:%d,容量:%d,数组地址:%p\n", len(s1), cap(s1), s1)
s1 = append(s1, 5)
fmt.Printf("长度:%d,容量:%d,数组地址:%p\n", len(s1), cap(s1), s1)
s1 = append(s1, 6)
fmt.Printf("长度:%d,容量:%d,数组地址:%p\n", len(s1), cap(s1), s1)
s1 = append(s1, 7)
fmt.Printf("长度:%d,容量:%d,数组地址:%p\n", len(s1), cap(s1), s1)
s1 = append(s1, 8)
fmt.Printf("长度:%d,容量:%d,数组地址:%p\n", len(s1), cap(s1), s1)


/*output
	长度:3,容量:3,数组地址:0xc00001e0c0
    长度:4,容量:6,数组地址:0xc00001a120
    长度:5,容量:6,数组地址:0xc00001a120
    长度:6,容量:6,数组地址:0xc00001a120
    长度:7,容量:12,数组地址:0xc00005c060
    长度:8,容量:12,数组地址:0xc00005c060
*/

切片变换过程

img

copy

  • 切片元素的赋值可利用copy函数
a1 := []{1,1,1,1,1}
b1 := []{-1,-1,-1}
copy(a1, b1)  // 将 b1 复制到 a1
// a1 : [-1,-1,-1,1,1]

a2 := []{2,2,2,2,2}
b2 := []{-2,-2,-2}
copy(b2, a2)  // 将 b1 复制到 a1
// b2 : [2,2,2]

注意:要理解复制到的含义。

  • copy函数只涉及元素值的拷贝,不涉新空间的创造

  • copy的两个参数必须是slice,不能是数组

其他

slice是通过指向底层数组来存储数据,而且可能有多个slice指向同一个底层数组。如果有任一切片指向这个数组,底层数组就因处于使用状态而无法被删除。

极端情况,很小的切片指向很大底层数组,会造成空间的浪费。

map

  • map(映射)是Go语言提供的key-value(键值对)形式的无序集合。

  • map的底层是Hash(哈希)表。

  • 键值对的键有唯一性的要求,通过键来获取值和更新值。

定义形式

map[k]v

  • k是键,同一mao中所有的key是同一数据类型,而且必须能进行==的比较运算 。
  • boll类型作为k并不灵活,而浮点型作为k,可能会因为精度问题而导致异常。

基本操作

创建map

// 方式一
m1 := make(map[string]int)

// 方式二
m2 := map[string]int{
    "k1" : 11,
    "k2" : 22,
}

访问元素

map[k], 比如val,ok = m2["k1"]。根据key找val,如果key不存在,ok=false。

添加元素

map[key] = value

注意:key如果存在,则用value更新值。如果不存在,则添加key-value对。

删除元素

delete(map, k),比如delete[m2, "k2"]

注意:delete函数删除不存在的key时,不会出错。

遍历map

for k, v := range m2 {
    fmt.Println(k, v)
}

特点

  • map在元素赋值之前必须初始化。使用上面两种方式均可。如果只声明map,使用则会出错。

    var m1 map[string]int
    m1["k1"] = 12  // error: assignment to nil map 
    
  • map的默认初始值是nil,未初始化的map是nil。尽管如此,未初始化的map执行删除元素、len操作、range操作或查找元素时都不会报错。但未初始化之前进行元素赋值操作会出错。

struct

  • struct是复合类型,而非引用类型。复合类型是值传递,而引用类型是引用传递。

结构体定义

type Person struct {
	name string
	gender int
	age int
}

var p1 Person

p2 := Person{"Jack", 1, 18}

p3 := Person{name:"Scott", gender:1, age:18}

注意:struct成员的可见性是通过首字母大小写控制,首字母小写仅本报可见,首字母大写则包外也可访问。

成员访问

p3.name

结构体指针

var pp *Person

注意:结构体指针必须初始化后才可以使用,因为如果仅仅声明结构体指针类型变量,其默认值初始值是nil。

pp := new(Person),创建指向Person结构体的指针pp。

pp.name = "Json",结构体指针访问成员也是直接.运算符,这是Go的语法糖。

make和new

make函数用于slice、map和chan进行内存分配,它返回的不是指针,而是上面三个类型中的某一个类型本身。

new函数返回初始化的类型对应的指针,new函数主要用于struct初始化中,其他场景英语较少。

参考

《快学 Go 语言》第 7 课

重学Go语言 | Slice全面讲解

Go微服务实战

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

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

相关文章

蓝桥杯单片机第十三届国赛 真题+代码

注&#xff1a;PWM没搞出来 iic.c /* # I2C代码片段说明1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。2. 参赛选手可以自行编写相关代码或以该代码为基础&#xff0c;根据所选单片机类型、运行速度和试题中对单片机时钟频率的要求&#xff0c;进行代码调试和修…

​《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(9)-Fiddler如何设置捕获Https会话​

1.简介 由于近几年来各大网站越来越注重安全性都改成了https协议&#xff0c;不像前十几年前直接是http协议直接裸奔在互联网。还有的小伙伴或者童鞋们按照上一篇宏哥的配置都配置好了&#xff0c;想大展身手抓一下百度的包&#xff0c;结果一试傻眼了&#xff0c;竟然毛都没有…

ChatGML2新手速通!自定义魔法指令,一键开启大模型奇妙之旅!

我们的宗旨是&#xff01; 让人人都有大模型用&#xff01; 让人人都能轻松上手使用大模型&#xff01; ChatGLM2-6B是中英双语对话模型 ChatGLM-6B 的第二代版本&#xff0c;相比第一代&#xff0c;第二代支持更强大的性能、更长的上下文、更高效的推理。 飞桨AI Studio已支…

数据库转换分析软件:EasyMorph 5.X Crack

EasyMorph 为您和您的团队提供数据超能力。无需编码技能。不要问 IT 人员。 自己做。 内置动作 即使您不是 IT 专家&#xff0c;也可以从任何地方检索数据并自动执行复杂的数据转换 无需 SQL 或编程知识 — 设计简单且 100% 可视化 减少对企业IT部门的依赖&#xff0c;减少繁琐…

揭秘爱数AnyShare认知助手:大模型深度产品化,深化人与机器的“分工协作”

文 | 智能相对论 作者 | 叶远风 大模型竞逐日趋白热化&#xff0c;百模大战热闹非凡。 但是&#xff0c;对产业主体或者普通看客而言&#xff0c;大模型究竟如何改变一线业务、实现工作方式的变革甚至组织转型&#xff0c;很多人并没有具象化的认知。 技术厉害、产品牛&…

HEVC 率失真优化技术介绍

背景 为了将具有庞大数据量的视频在有限信道内传输、存储、高压缩率的编码算法往往会造成编码重建视频与原始视频存在差别&#xff0c;即重建视频产生失真&#xff0c;该类压缩被称为有损压缩。对于有损压缩算法&#xff0c;其性能需要根据编码输出的比特率和编码带来的失真度…

Mongo 集群部署

1. 集群架构 # mongos:提供路由数据库集群请求的入口,所有的请求都通过 mongos 进行协调,不需要在应用程序添加一个路由选择器,mongos 自己就是一个请求分发中心,它负责把对应的数据请求转发到对应的 shard 服务器上。在生产环境通常有多 mongos 作为请求的入口,防止其中…

消息服务概述

消息服务的作用&#xff1a; 在多数应用尤其是分布式系统中&#xff0c;消息服务是不可或缺的重要部分&#xff0c;它使用起来比较简单&#xff0c;同时解决了不少难题&#xff0c;例如异步处理、应用解耦、流量削锋、分布式事务管理等&#xff0c;使用消息服务可以实现一个高…

适用于 Linux 系统的综合日志审计和报告

从 Linux 设备以及各种其他日志源收集日志&#xff0c;并从单个控制台监控它们&#xff0c;以轻松了解网络活动。 Linux 系统日志如何工作 Linux 操作系统日志包含多个日志文件&#xff0c;其中包含有关网络中发生的事件的详细信息。在服务器上执行的每个操作都可以通过日志进…

【C语言】从零开始学习数组

&#x1f341; 博客主页:江池俊的博客 &#x1f4ab;收录专栏&#xff1a;C语言——探索高效编程的基石 &#x1f4bb; 其他专栏&#xff1a;数据结构探索 &#x1f4a1;代码仓库&#xff1a;江池俊的代码仓库 &#x1f3aa; 社区&#xff1a;C/C之家社区 &#x1f341; 如果觉…

【项目方案】OpenAI流式请求实现方案

文章目录 实现目的效果比对非stream模式stream模式实现方案方案思路总体描述前端方案对比event-source-polyfill代码示例前端实现遇到的问题与解决方法后端参考资料时序图关键代码示例后端实现时遇到的问题与解决方法实现目的 stream是OpenAI API中的一个参数,用于控制请求的…

UE5.1.1 创建C++项目失败

因一直使用Unity开发环境&#xff0c;安装Unreal后&#xff0c;并未详细配置过其开发环境&#xff0c;默认创建蓝图工程无异常&#xff0c;但创建UE C项目时总共遇到两个错误&#xff1a; 错误一 Running /Epic/UE/UE_5.1/Engine/Build/BatchFiles/Build.bat -projectfiles -…

LeetCode 75 第十二题(11)盛最多水的容器

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 配合着示例给出的图片我们可以得知找出盛水最多的容器是什么意思,给一个数组,找出数组中两个元素能围成的最大的矩阵面积是多少. 比较直观的想法是套两层for循环暴力解出来,但是这题是中等难度题,一般中等题是没法用暴力得…

OSI七层模型——第2层数据链路层

目录 1 数据链路层的用途 1.1 数据链路层 1.2 IEEE 802LAN/MAN 数据链路子层 1.3 提供介质访问 1.4 数据链路层标准 2 拓扑 2.1 物理和逻辑拓扑 2.2 WAN 拓扑 2.3 点对点 WAN 拓扑 2.4 LAN 拓扑 2.5 半双工和全双工通信 2.6 访问控制方法 2.7 基于竞争的访问 - CS…

Excel录制宏批处理:避免重复工作,轻松提升效率

在处理大量数据时&#xff0c;我们常常需要进行一些重复且繁琐的操作&#xff0c;这不仅费时费力&#xff0c;还容易出错。而Excel的录制宏批处理功能可以帮助我们避免这些重复的工作&#xff0c;提高工作效率。本文将为您介绍如何使用Excel的录制宏批处理功能&#xff0c;让您…

【CesiumJS材质】(1)圆扩散

效果示例 最佳实践&#xff1a; 其他效果&#xff1a; 要素说明&#xff1a; 代码 /** Date: 2023-07-21 15:15:32* LastEditors: ReBeX 420659880qq.com* LastEditTime: 2023-07-27 11:13:17* FilePath: \cesium-tyro-blog\src\utils\Material\EllipsoidFadeMaterialP…

在CSDN学Golang云原生(Kubernetes声明式资源管理Kustomize)

一&#xff0c;生成资源 在 Kubernetes 中&#xff0c;我们可以通过 YAML 或 JSON 文件来定义和创建各种资源对象&#xff0c;例如 Pod、Service、Deployment 等。下面是一个简单的 YAML 文件示例&#xff0c;用于创建一个 Nginx Pod&#xff1a; apiVersion: v1 kind: Pod m…

基于Velocity开发代码生成器

一、引言 在项目开发中&#xff0c;我们有碰到大量的简单、重复的增删改查需求&#xff0c;通过阅读若依框架https://github.com/yangzongzhuan/RuoYi 的代码生成器实现&#xff0c;结合我项目所用的技术栈&#xff0c;开发出本项目的代码生成器。 二、Velocity 简单介绍 1、…

【C++入门】浅谈类、对象和 this 指针

文章目录 一、前言二、类1. 基本概念2. 类的封装3. 使用习惯成员函数定义习惯成员变量命名习惯 三、对象1. 基本概念2. 类对象的存储规则 四、this 指针1. 基本概念2. 注意事项3. 经典习题4. 常见面试题 一、前言 在 C 语言中&#xff0c;我们用结构体来描述一个事物的多种属性…

Markdown常用标签及其用途-有示例

Markdown常用标签及其用途 Markdown是一种轻量级标记语言&#xff0c;具有简洁易读的特点。下面是一些常用的Markdown标签以及它们的用途&#xff0c;并附带一些示例&#xff1a; 标题 用于创建不同级别的标题&#xff0c;可通过添加一到六个#符号来表示不同级别的标题。 #…