<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh"><generator uri="https://jekyllrb.com/" version="3.9.3">Jekyll</generator><link href="https://lanyily.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://lanyily.github.io/" rel="alternate" type="text/html" hreflang="zh" /><updated>2023-12-08T03:43:12+00:00</updated><id>https://lanyily.github.io/feed.xml</id><title type="html">Gelei Blog</title><subtitle>格蕾的C++技术博客, 涉及C++基础, 计算机图形学, 三维动作捕捉, 游戏引擎开发, 音视频处理等
</subtitle><author><name>Ge Lei</name><email>&lt;mail@domain.tld&gt;</email></author><entry><title type="html">golang圣经第二章：程序结构</title><link href="https://lanyily.github.io/golang/2023-10-13-golang/" rel="alternate" type="text/html" title="golang圣经第二章：程序结构" /><published>2023-10-13T00:00:00+00:00</published><updated>2023-10-13T00:00:00+00:00</updated><id>https://lanyily.github.io/golang/golang</id><content type="html" xml:base="https://lanyily.github.io/golang/2023-10-13-golang/">&lt;p&gt;本章介绍Go语言程序的命名，声明，基本元素结构、变量、新类型定义、包和文件、以及作用域&lt;/p&gt;

&lt;h1 id=&quot;21-命名&quot;&gt;2.1 命名&lt;/h1&gt;

&lt;p&gt;变量名称有大小写区分&lt;/p&gt;

&lt;h3 id=&quot;关键字&quot;&gt;关键字&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;break      default       func     interface   select
case       defer         go       map         struct
chan       else          goto     package     switch
const      fallthrough   if       range       type
continue   for           import   return      var
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;预定义的名字&quot;&gt;预定义的名字&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;内建常量: true false iota nil

内建类型: int int8 int16 int32 int64
          uint uint8 uint16 uint32 uint64 uintptr
          float32 float64 complex128 complex64
          bool byte rune string error

内建函数: make len cap new append copy close delete
          complex real imag
          panic recover
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;定义域&quot;&gt;定义域&lt;/h3&gt;

&lt;p&gt;如果一个名字是在函数内部定义，那么它就只在函数内部有效。&lt;/p&gt;

&lt;p&gt;如果是在函数外部定义，那么将在当前包的所有文件中都可以访问。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;名字的开头字母的大小写决定了名字在包外的可见性&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;如果一个名字是大写字母开头的（必须是在函数外部定义的包级名字；包级函数名本身也是包级名字），那么它将是导出的，也就是说可以被外部的包访问，例如fmt包的Printf函数就是导出的，可以在fmt包外部访问。&lt;/p&gt;

&lt;p&gt;包本身的名字一般总是用小写字母。&lt;/p&gt;

&lt;h3 id=&quot;命名&quot;&gt;命名&lt;/h3&gt;

&lt;p&gt;命名一般采用大小写分隔而不是下划线分隔&lt;/p&gt;

&lt;p&gt;QuoteRuneToASCII和parseRequestLine&lt;/p&gt;

&lt;p&gt;缩略词一般大小写一致，如htmlEscape、HTMLEscape或escapeHTML，但不会是escapeHtml。&lt;/p&gt;

&lt;h1 id=&quot;22-声明&quot;&gt;2.2 声明&lt;/h1&gt;

&lt;p&gt;Go语言主要有四种类型的声明语句：var、const、type和func，分别对应变量、常量、类型和函数实体对象的声明&lt;/p&gt;

&lt;h3 id=&quot;函数声明&quot;&gt;函数声明&lt;/h3&gt;

&lt;p&gt;一个函数的声明由一个函数名字、参数列表（由函数的调用者提供参数变量的具体值）、一个可选的返回值列表和包含函数定义的函数体组成。&lt;/p&gt;

&lt;p&gt;如果函数没有返回值，那么返回值列表是省略的。&lt;/p&gt;

&lt;h1 id=&quot;23-变量&quot;&gt;2.3 变量&lt;/h1&gt;

&lt;h2 id=&quot;基本声明&quot;&gt;基本声明&lt;/h2&gt;

&lt;h3 id=&quot;变量声明&quot;&gt;变量声明&lt;/h3&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;变量名字&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;类型&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;表达式&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;其中“&lt;em&gt;类型&lt;/em&gt;”或“&lt;em&gt;= 表达式&lt;/em&gt;”两个部分可以省略其中的一个。如果省略的是类型信息，那么将根据初始化表达式来推导变量的类型信息。如果初始化表达式被省略，那么将用零值初始化该变量。 数值类型变量对应的零值是0，布尔类型变量对应的零值是false，字符串类型对应的零值是空字符串，接口或引用类型（包括slice、指针、map、chan和函数）变量对应的零值是nil。数组或结构体等聚合类型对应的零值是每个元素或字段都是对应该类型的零值。&lt;/p&gt;

&lt;h3 id=&quot;声明多个&quot;&gt;声明多个&lt;/h3&gt;

&lt;p&gt;函数返回值也可以初始化&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;                 &lt;span class=&quot;c&quot;&gt;// int, int, int&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;four&quot;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// bool, float64, string&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// os.Open returns a file and an error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;不要混淆多个变量的声明和元组的多重赋值（§2.4.1），后者是将右边各个表达式的值赋值给左边对应位置的各个变量：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;i, j = j, i // 交换 i 和 j 的值
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;231-简短变量声明&quot;&gt;2.3.1 简短变量声明&lt;/h2&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;                  &lt;span class=&quot;c&quot;&gt;// an int&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;boiling&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// a float64&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;names&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;简短变量声明语句也可以用来声明和初始化一组变量：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;i, j := 0, 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;“:=”是一个变量声明语句，而“=”是一个变量赋值操作&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;简短变量声明左边的变量可能并不是全部都是刚刚声明的。如果有一些已经在相同的词法域声明过了，那么简短变量声明语句对这些已经声明过的变量就只有赋值行为了。&lt;/p&gt;

&lt;p&gt;在下面的代码中，第一个语句声明了in和err两个变量。在第二个语句只声明了out一个变量，然后对已经声明的err进行了赋值操作。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;in, err := os.Open(infile)
// ...
out, err := os.Create(outfile)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;简短变量声明语句中必须至少要声明一个新的变量，下面的代码将不能编译通过：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;f, err := os.Open(infile)
// ...
f, err := os.Create(outfile) // compile error: no new variables
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;简短变量声明语句只有对已经在同级词法域声明过的变量才和赋值操作语句等价，如果变量是在外部词法域声明的，那么简短变量声明语句将会在当前词法域重新声明一个新的变量。&lt;/p&gt;

&lt;p&gt;在Go语言中，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&lt;/code&gt; 是两种不同的变量声明和赋值操作符，它们的用法和含义有一些不同。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;result := add(3, 5)&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这是一个使用短变量声明操作符 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt; 的语句。它的主要特点是：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;它用于声明并初始化一个新的变量 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;result&lt;/code&gt;。&lt;/li&gt;
  &lt;li&gt;变量的类型是由右侧的表达式的返回值类型来推断的，因此 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;result&lt;/code&gt; 的类型将由 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add(3, 5)&lt;/code&gt; 的返回值类型决定。&lt;/li&gt;
  &lt;li&gt;这个操作符通常在函数内部使用，用于创建一个新的变量并为其赋初值。&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var result = add(3, 5)&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这是使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var&lt;/code&gt; 关键字进行变量声明和初始化的语句。它的特点是：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;它显式指定了变量的类型，类型由 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var result&lt;/code&gt; 的部分决定，因此需要明确指定变量的类型。&lt;/li&gt;
  &lt;li&gt;右侧的表达式 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add(3, 5)&lt;/code&gt; 用于初始化变量 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;result&lt;/code&gt; 的值。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;因此，主要的区别在于类型的推断和声明方式：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;result := add(3, 5)&lt;/code&gt; 会自动推断 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;result&lt;/code&gt; 的类型，不需要显式指定。&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var result = add(3, 5)&lt;/code&gt; 显式指定了变量的类型，适用于需要明确指定类型的情况。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;在实际使用中，通常会根据情况选择适当的方式。如果你希望变量的类型由赋值表达式自动推断，可以使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt;，而如果你需要明确指定类型，可以使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var&lt;/code&gt;。&lt;/p&gt;

&lt;h2 id=&quot;232-指针&quot;&gt;2.3.2 指针&lt;/h2&gt;

&lt;p&gt;函数可以传指针，不能传引用&lt;/p&gt;

&lt;p&gt;任何类型的指针的零值都是nil。&lt;/p&gt;

&lt;p&gt;变量有时候被称为可寻址的值。即使变量由表达式临时生成，那么表达式也必须能接受&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&lt;/code&gt;取地址操作。&lt;/p&gt;

&lt;p&gt;指针之间也是可以进行相等测试的，只有当它们指向同一个变量或全部是nil时才相等。&lt;/p&gt;

&lt;p&gt;在Go语言中，返回函数中局部变量的地址也是安全的，如下，因为指针p依然引用这个变量。&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;flag&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;strings&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;n&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;omit newline&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;separator&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;233-new函数&quot;&gt;2.3.3 new函数&lt;/h2&gt;

&lt;p&gt;语法糖，不是新的基础概念&lt;/p&gt;

&lt;p&gt;调用内建的new函数。表达式new(T)将创建一个T类型的匿名变量，初始化为T类型的零值，然后返回变量地址，返回的指针类型为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*T&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;每次调用new函数都是返回一个&lt;strong&gt;新的变量&lt;/strong&gt;的地址&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;c&quot;&gt;// p, *int 类型, 指向匿名的 int 变量&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// &quot;0&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;          &lt;span class=&quot;c&quot;&gt;// 设置 int 匿名变量的值为 2&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// &quot;2&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;用new创建变量和普通变量声明语句方式创建变量没有什么区别，除了不需要声明一个临时变量的名字外，我们还可以在表达式中使用new(T)&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dummy&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dummy&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;重定义&quot;&gt;重定义&lt;/h3&gt;

&lt;p&gt;由于new只是一个预定义的函数，它并不是一个关键字，因此我们可以将new名字重新定义为别的类型。例如下面的例子：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;func delta(old, new int) int { return new - old }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;由于new被定义为int类型的变量名，因此在delta函数内部是无法使用内置的new函数的。&lt;/p&gt;

&lt;h2 id=&quot;234-变量的生命周期&quot;&gt;2.3.4 变量的生命周期&lt;/h2&gt;

&lt;p&gt;对于在包一级声明的变量来说，它们的生命周期和整个程序的运行周期是一致的。&lt;/p&gt;

&lt;p&gt;局部变量的生命周期则是动态的：每次从创建一个新变量的声明语句开始，直到该变量不再被引用为止，然后变量的存储空间可能被回收。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;函数的参数变量&lt;/strong&gt;和&lt;strong&gt;返回值变量&lt;/strong&gt;都是&lt;strong&gt;局部变量&lt;/strong&gt;。它们在函数每次被调用的时候创建。&lt;/p&gt;

&lt;p&gt;末尾的参数变量后面显式插入逗号时，最后插入的逗号不会导致编译错误，这是Go编译器的一个特性&lt;/p&gt;

&lt;h3 id=&quot;垃圾回收机制&quot;&gt;垃圾回收机制&lt;/h3&gt;

&lt;p&gt;基本的实现思路是，从每个包级的变量和每个当前运行函数的每一个局部变量开始，通过指针或引用的访问路径遍历，是否可以找到该变量。如果不存在这样的访问路径，那么说明该变量是不可达的，也就是说它是否存在并不会影响程序后续的计算结果。&lt;/p&gt;

&lt;p&gt;因为一个变量的有效周期只取决于是否可达，因此一个循环迭代内部的局部变量的生命周期可能超出其局部作用域。同时，局部变量可能在函数返回之后依然存在。&lt;/p&gt;

&lt;h2 id=&quot;235-栈和堆的分配&quot;&gt;2.3.5 栈和堆的分配&lt;/h2&gt;

&lt;p&gt;编译器会自动选择在栈上还是在堆上分配局部变量的存储空间，但可能令人惊讶的是，这个选择并不是由用var还是new声明变量的方式决定的。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;var global *int

func f() {
    var x int
    x = 1
    global = &amp;amp;x
}

func g() {
    y := new(int)
    *y = 1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;f函数里的x变量必须在堆上分配，因为它在函数退出后依然可以通过包一级的global变量找到，虽然它是在函数内部定义的；用Go语言的术语说，这个x局部变量从函数f中&lt;strong&gt;逃逸&lt;/strong&gt;了。&lt;/p&gt;

&lt;p&gt;相反，当g函数返回时，变量&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*y&lt;/code&gt;将是不可达的，也就是说可以马上被回收的。因此，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*y&lt;/code&gt;并没有从函数g中逃逸，编译器可以选择在栈上分配&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*y&lt;/code&gt;的存储空间（译注：也可以选择在堆上分配，然后由Go语言的GC回收这个变量的内存空间），虽然这里用的是new方式。&lt;/p&gt;

&lt;p&gt;其实在任何时候，你并不需为了编写正确的代码而要考虑变量的逃逸行为，要记住的是，逃逸的变量需要&lt;strong&gt;额外分配内存&lt;/strong&gt;，同时对性能的优化可能会产生细微的影响。&lt;/p&gt;

&lt;h1 id=&quot;24-赋值&quot;&gt;2.4 赋值&lt;/h1&gt;

&lt;h2 id=&quot;241-递增递减&quot;&gt;2.4.1 递增，递减&lt;/h2&gt;

&lt;p&gt;数值变量也可以支持&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;++&lt;/code&gt;递增和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--&lt;/code&gt;递减语句，但是自增和自减是语句，而不是表达式，因此&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x = i++&lt;/code&gt;之类的表达式是错误的&lt;/p&gt;

&lt;h2 id=&quot;242-元组赋值&quot;&gt;2.4.2 元组赋值&lt;/h2&gt;

&lt;p&gt;元组赋值是另一种形式的赋值语句，它允许同时更新多个变量的值。在赋值之前，赋值语句右边的所有表达式将会先进行求值，然后再统一更新左边对应变量的值。&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 计算两个整数值的的最大公约数&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gcd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// 计算斐波纳契数列（Fibonacci）的第N个数&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;有些表达式会产生多个值，比如调用一个有多个返回值的函数。当这样一个函数调用出现在元组赋值右边的表达式中时（译注：右边不能再有其它表达式），左边变量的数目必须和右边一致。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;f, err = os.Open(&quot;foo.txt&quot;) // function call returns two values
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果map查找（§4.3）、类型断言（§7.10）或通道接收（§8.4.2）出现在赋值语句的右边，它们都可能会产生两个结果，有一个额外的布尔结果表示操作是否成功：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;v, ok = m[key]             // map lookup
v, ok = x.(T)              // type assertion
v, ok = &amp;lt;-ch               // channel receive
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;也可能只产生一个结果。对于只产生一个结果的情形，map查找失败时会返回零值，类型断言失败时会发生运行时panic异常，通道接收失败时会返回零值（阻塞不算是失败）&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;v = m[key]                // map查找，失败时返回零值
v = x.(T)                 // type断言，失败时panic异常
v = &amp;lt;-ch                  // 管道接收，失败时返回零值（阻塞不算是失败）

_, ok = m[key]            // map返回2个值
_, ok = mm[&quot;&quot;], false     // map返回1个值
_ = mm[&quot;&quot;]                // map返回1个值
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;和变量声明一样，我们可以用下划线空白标识符&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt;来丢弃不需要的值。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;_, err = io.Copy(dst, src) // 丢弃字节数
_, ok = x.(T)              // 只检测类型，忽略具体值
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;243-可赋值性&quot;&gt;2.4.3 可赋值性&lt;/h2&gt;

&lt;p&gt;不管是隐式还是显式地赋值，在赋值语句左边的变量和右边最终的求到的值必须有相同的数据类型。更直白地说，只有右边的值对于左边的变量是可赋值的，赋值语句才是允许的。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;目前规则&lt;/strong&gt;：类型必须完全匹配，nil可以赋值给任何指针或引用类型的变量，常量则有更灵活的赋值规则，因为这样可以避免不必要的显式的类型转换。&lt;/p&gt;

&lt;p&gt;对于两个值是否可以用&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;==&lt;/code&gt;或&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!=&lt;/code&gt;进行相等比较的能力也和可赋值能力有关系：对于任何类型的值的相等比较，第二个值必须是对第一个值类型对应的变量是可赋值的，反之亦然。&lt;/p&gt;

&lt;h1 id=&quot;25-类型&quot;&gt;2.5 类型&lt;/h1&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;type 类型名字 底层类型
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;类型声明语句一般出现在包一级，因此如果新创建的类型名字的首字符大写，则在包外部也可以使用。&lt;/p&gt;

&lt;h2 id=&quot;251-类型转换&quot;&gt;2.5.1 类型转换&lt;/h2&gt;

&lt;p&gt;在任何情况下，运行时不会发生转换失败的错误，错误只会发生在编译阶段&lt;/p&gt;

&lt;p&gt;比较运算符&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;==&lt;/code&gt;和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;&lt;/code&gt;也可以用来比较一个命名类型的变量和另一个有相同类型的变量，或有着相同底层类型的未命名类型的值之间做比较。但是如果两个值有着不同的类型，则不能直接进行比较：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Go&quot;&gt;var c Celsius
var f Fahrenheit
fmt.Println(c == 0)          // &quot;true&quot;
fmt.Println(f &amp;gt;= 0)          // &quot;true&quot;
fmt.Println(c == f)          // compile error: type mismatch
fmt.Println(c == Celsius(f)) // &quot;true&quot;!
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&quot;26-包和文件&quot;&gt;2.6 包和文件&lt;/h1&gt;

&lt;p&gt;每个包都对应一个独立的名字空间。例如，在image包中的Decode函数和在unicode/utf16包中的 Decode函数是不同的。要在外部引用该函数，必须显式使用image.Decode或utf16.Decode形式访问。&lt;/p&gt;

&lt;p&gt;包还可以让我们通过控制哪些名字是外部可见的来隐藏内部实现信息。在Go语言中，一个简单的规则是：如果一个名字是大写字母开头的，那么该名字是导出的（因为汉字不区分大小写，因此汉字开头的名字是没有导出的）。&lt;/p&gt;

&lt;h2 id=&quot;261-包注释&quot;&gt;2.6.1 包注释&lt;/h2&gt;

&lt;p&gt;在每个源文件的包声明前紧跟着的注释是包注释（§10.7.4）。通常，包注释的第一句应该先是包的功能概要说明。一个包通常只有一个源文件有包注释（如果有多个包注释，目前的文档工具会根据源文件名的先后顺序将它们链接为一个包注释）。如果包注释很大，通常会放到一个独立的doc.go文件中。&lt;/p&gt;

&lt;h2 id=&quot;262-导入包&quot;&gt;2.6.2 导入包&lt;/h2&gt;

&lt;p&gt;除了包的导入路径，每个包还有一个包名，包名一般是短小的名字（并不要求包名是唯一的），包名在包的声明处指定。按照惯例，一个包的名字和包的导入路径的最后一个字段相同&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;如果导入了一个包，但是又没有使用该包将被当作一个编译错误处理。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这种强制规则可以有效减少不必要的依赖，虽然在调试期间可能会让人讨厌，因为删除一个类似log.Print(“got here!”)的打印语句可能导致需要同时删除log包导入声明，否则，编译器将会发出一个错误。在这种情况下，我们需要将不必要的导入删除或注释掉&lt;/p&gt;

&lt;h2 id=&quot;263-包的初始化&quot;&gt;2.6.3 包的初始化&lt;/h2&gt;

&lt;p&gt;包的初始化是通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init()&lt;/code&gt; 函数来实现的。每个包可以包含一个或多个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init()&lt;/code&gt; 函数，这些函数会在程序启动时自动执行，无需显式调用。&lt;/p&gt;

&lt;p&gt;初始化函数的格式如下：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 初始化代码&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;包中的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init()&lt;/code&gt; 函数会在包被导入时执行，每个包的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init()&lt;/code&gt; 函数按照导入的顺序执行，但每个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init()&lt;/code&gt; 函数仅执行一次。这使得包可以进行一些初始化工作，如设置全局变量、连接数据库、或执行其他必要的操作。&lt;/p&gt;

&lt;p&gt;初始化函数对于包的用户是透明的，它们不需要显式调用，而是在包被导入时自动执行。&lt;/p&gt;

&lt;h1 id=&quot;27-作用域&quot;&gt;2.7 作用域&lt;/h1&gt;

&lt;p&gt;一个声明语句将程序中的实体和一个名字关联，比如一个函数或一个变量。&lt;/p&gt;

&lt;p&gt;声明语句的&lt;strong&gt;作用域&lt;/strong&gt;是指&lt;strong&gt;源代码中可以有效使用这个名字的范围&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;不要将作用域和生命周期混为一谈。声明语句的作用域对应的是一个源代码的文本区域；它是一个&lt;strong&gt;编译时&lt;/strong&gt;的属性。一个变量的生命周期是指程序运行时变量存在的有效时间段，在此时间区域内它可以被程序的其他部分引用；是一个&lt;strong&gt;运行时&lt;/strong&gt;的概念。&lt;/p&gt;

&lt;h2 id=&quot;271-作用域导致的隐晦的错误&quot;&gt;2.7.1 作用域导致的隐晦的错误&lt;/h2&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cwd&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Getwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// NOTE: wrong!&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatalf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;os.Getwd failed: %v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Working directory = %s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;上述代码中，虽然cwd在外部已经声明过，但是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt;语句还是将cwd和err重新声明为新的局部变量。因为内部声明的cwd将屏蔽外部的声明，因此上面的代码并不会正确更新包级声明的cwd变量。&lt;/p&gt;

&lt;p&gt;最直接的解决方法是通过单独声明err变量，来避免使用&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt;的简短声明方式：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cwd&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Getwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatalf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;os.Getwd failed: %v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>Ge Lei</name><email>&lt;mail@domain.tld&gt;</email></author><category term="golang" /><summary type="html">本章介绍Go语言程序的命名，声明，基本元素结构、变量、新类型定义、包和文件、以及作用域</summary></entry><entry><title type="html">golang圣经第一章：入门</title><link href="https://lanyily.github.io/golang/2023-10-12-golang/" rel="alternate" type="text/html" title="golang圣经第一章：入门" /><published>2023-10-12T00:00:00+00:00</published><updated>2023-10-12T00:00:00+00:00</updated><id>https://lanyily.github.io/golang/golang</id><content type="html" xml:base="https://lanyily.github.io/golang/2023-10-12-golang/">&lt;p&gt;Go语言（或 Golang）起源于 2007 年，并在 2009 年正式对外发布。Go 是非常年轻的一门语言，它的主要目标是“兼具 Python 等动态语言的开发速度和 C/C++ 等编译型语言的性能与安全性”。&lt;/p&gt;

&lt;h1 id=&quot;11-hello-world&quot;&gt;1.1 hello world&lt;/h1&gt;

&lt;p&gt;go是静态编译&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-cmd&quot;&gt;go run test.go
go build test.go
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;go build会生成可执行的二进制文件&lt;/p&gt;

&lt;p&gt;必须恰当导入需要的包，缺少了必要的包或者导入了不需要的包，程序都无法编译通过。这项严格要求避免了程序开发过程中引入未使用的包（Go 语言编译过程没有警告信息，争议特性之一）。&lt;/p&gt;

&lt;h3 id=&quot;换行符&quot;&gt;换行符&lt;/h3&gt;

&lt;p&gt;Go 语言不需要在语句或者声明的末尾添加分号，除非一行上有多条语句。实际上，编译器会主动把特定符号后的换行符转换为分号，因此换行符添加的位置会影响 Go 代码的正确解析&lt;/p&gt;

&lt;p&gt;函数的左括号 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{&lt;/code&gt; 必须和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;func&lt;/code&gt; 函数声明在同一行上，且位于末尾，不能独占一行，而在表达式 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x+y&lt;/code&gt; 中，可在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; 后换行，不能在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; 前换行（译注：以+结尾的话不会被插入分号分隔符，但是以 x 结尾的话则会被分号分隔符，从而导致编译错误）。&lt;/p&gt;

&lt;p&gt;代码编辑器会自动调用&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gofmt&lt;/code&gt;工具把代码格式化为标准格式，这个格式化工具没有任何可以调整代码格式的参数，固定死的&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go原生支持unicode&lt;/strong&gt;&lt;/p&gt;

&lt;h1 id=&quot;12-命令行参数&quot;&gt;1.2 命令行参数&lt;/h1&gt;

&lt;h3 id=&quot;数组&quot;&gt;数组&lt;/h3&gt;

&lt;p&gt;go语言采用左闭右开形式&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s[m:n]&lt;/code&gt; 这个切片，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0≤m≤n≤len(s)&lt;/code&gt;，包含 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n-m&lt;/code&gt; 个元素。&lt;/p&gt;

&lt;p&gt;如果省略切片表达式的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m&lt;/code&gt; 或 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt;，会默认传入 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; 或 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;len(s)&lt;/code&gt;，因此前面的切片可以简写成 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os.Args[1:]&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;os包&quot;&gt;os包&lt;/h3&gt;

&lt;p&gt;命令行参数可以从os包的Args变量获取&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os.Args&lt;/code&gt;是一个字符串的切片&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;//命令本身的名字&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3&gt;++–&lt;/h3&gt;

&lt;p&gt;自增语句 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i++&lt;/code&gt; 给 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i&lt;/code&gt; 加 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;这和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i+=1&lt;/code&gt; 以及 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i=i+1&lt;/code&gt; 都是等价的。对应的还有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i--&lt;/code&gt; 给 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i&lt;/code&gt; 减 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;。它们是语句，而不像 C 系的其它语言那样是表达式。&lt;/p&gt;

&lt;p&gt;所以 &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;j=i++&lt;/code&gt; 非法&lt;/strong&gt;，而且 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;++&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--&lt;/code&gt; 都只能放在变量名后面，因此 &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--i&lt;/code&gt; 也非法&lt;/strong&gt;。&lt;/p&gt;

&lt;h3 id=&quot;循环&quot;&gt;循环&lt;/h3&gt;

&lt;p&gt;go只有for循环&lt;/p&gt;

&lt;h4 id=&quot;显示索引&quot;&gt;显示索引&lt;/h4&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialization&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// zero or more statements&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; 循环三个部分不需括号包围。大括号强制要求，左大括号必须和 &lt;em&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post&lt;/code&gt;&lt;/em&gt; 语句在同一行。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;initialization&lt;/code&gt;&lt;/em&gt; 语句是可选的，在循环开始前执行。&lt;em&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;initalization&lt;/code&gt;&lt;/em&gt; 如果存在，必须是一条 &lt;em&gt;简单语句&lt;/em&gt;（simple statement），即，短变量声明、自增语句、赋值语句或函数调用。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;condition&lt;/code&gt; 是一个布尔表达式（boolean expression），其值在每次循环迭代开始时计算。如果为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; 则执行循环体语句。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post&lt;/code&gt; 语句在循环体执行结束后执行，之后再次对 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;condition&lt;/code&gt; 求值。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;condition&lt;/code&gt; 值为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt; 时，循环结束。&lt;/p&gt;

&lt;p&gt;for 循环的这三个部分每个都可以省略，如果省略 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;initialization&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post&lt;/code&gt;，分号也可以省略：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// a traditional &quot;while&quot; loop&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;condition&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果连 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;condition&lt;/code&gt; 也省略了，像下面这样：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// a traditional infinite loop&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这就变成一个无限循环，尽管如此，还可以用其他方式终止循环，如一条 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;break&lt;/code&gt; 或 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return&lt;/code&gt; 语句。&lt;/p&gt;

&lt;h4 id=&quot;隐式索引&quot;&gt;隐式索引&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; 循环的另一种形式，在某种数据类型的区间（range）上遍历，如字符串或切片。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;echo&lt;/code&gt; 的第二版本展示了这种形式：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Echo2 prints its command-line arguments.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;os&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; &quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;每次循环迭代，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range&lt;/code&gt; 产生一对值；索引以及在该索引处的元素值。这个例子不需要索引，但 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range&lt;/code&gt; 的语法要求，要处理元素，必须处理索引。一种思路是把索引赋值给一个临时变量（如 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;temp&lt;/code&gt;）然后忽略它的值，但 Go 语言不允许使用无用的局部变量（local variables），因为这会导致编译错误。&lt;/p&gt;

&lt;p&gt;Go 语言中这种情况的解决方法是用 &lt;em&gt;空标识符&lt;/em&gt;（blank identifier），即 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt;（也就是下划线）。空标识符可用于在任何语法需要变量名但程序逻辑不需要的时候（如：在循环里）丢弃不需要的循环索引，并保留元素值。大多数的 Go 程序员都会像上面这样使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt; 写 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;echo&lt;/code&gt; 程序，因为隐式地而非显式地索引 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os.Args&lt;/code&gt;，容易写对。&lt;/p&gt;

&lt;h3 id=&quot;变量声明&quot;&gt;变量声明&lt;/h3&gt;

&lt;p&gt;声明一个变量有好几种方式，下面这些都等价：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;第一种形式，是一条短变量声明，最简洁，但只能用在函数内部，而不能用于包变量。&lt;/p&gt;

&lt;p&gt;第二种形式依赖于字符串的默认初始化零值机制，被初始化为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;&quot;&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;第三种形式用得很少，除非同时声明多个变量。&lt;/p&gt;

&lt;p&gt;第四种形式显式地标明变量的类型，当变量类型与初值类型相同时，类型冗余，但如果两者类型不同，变量类型就必须了。&lt;/p&gt;

&lt;p&gt;实践中一般使用前两种形式中的某个，初始值重要的话就显式地指定变量的类型，否则使用隐式初始化。&lt;/p&gt;

&lt;h1 id=&quot;13-查找重复的行&quot;&gt;1.3 查找重复的行&lt;/h1&gt;

&lt;h3 id=&quot;动词&quot;&gt;动词&lt;/h3&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;%d          十进制整数
%x, %o, %b  十六进制，八进制，二进制整数。
%f, %g, %e  浮点数： 3.141593 3.141592653589793 3.141593e+00
%t          布尔：true或false
%c          字符（rune） (Unicode码点)
%s          字符串
%q          带双引号的字符串&quot;abc&quot;或带单引号的字符'c'
%v          变量的自然形式（natural format）
%T          变量的类型
%%          字面上的百分号标志（无操作数）
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;格式化函数&quot;&gt;格式化函数&lt;/h3&gt;

&lt;p&gt;默认情况下，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Printf&lt;/code&gt; 不会换行。按照惯例，以字母 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; 结尾的格式化函数，如 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;log.Printf&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmt.Errorf&lt;/code&gt;，都采用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmt.Printf&lt;/code&gt; 的格式化准则。而以 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ln&lt;/code&gt; 结尾的格式化函数，则遵循 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Println&lt;/code&gt; 的方式，以跟 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%v&lt;/code&gt; 差不多的方式格式化参数，并在最后添加一个换行符。（译注：后缀 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; 指 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;format&lt;/code&gt;，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ln&lt;/code&gt; 指 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;line&lt;/code&gt;。）&lt;/p&gt;

&lt;h3 id=&quot;nil&quot;&gt;nil&lt;/h3&gt;

&lt;p&gt;nil属于内置值，相当于其他语言中的NULL&lt;/p&gt;</content><author><name>Ge Lei</name><email>&lt;mail@domain.tld&gt;</email></author><category term="golang" /><summary type="html">Go语言（或 Golang）起源于 2007 年，并在 2009 年正式对外发布。Go 是非常年轻的一门语言，它的主要目标是“兼具 Python 等动态语言的开发速度和 C/C++ 等编译型语言的性能与安全性”。</summary></entry><entry><title type="html">golang环境配置</title><link href="https://lanyily.github.io/golang/2023-10-11-golang/" rel="alternate" type="text/html" title="golang环境配置" /><published>2023-10-11T00:00:00+00:00</published><updated>2023-10-11T00:00:00+00:00</updated><id>https://lanyily.github.io/golang/golang</id><content type="html" xml:base="https://lanyily.github.io/golang/2023-10-11-golang/">&lt;p&gt;windows系统，使用vs code作为IDE，配置golang环境&lt;/p&gt;

&lt;h2 id=&quot;下载&quot;&gt;下载&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://go.dev/doc/install&quot;&gt;Download and install - The Go Programming Language&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;go1.21.3.windows-amd64&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;C:\Users\admin&amp;gt;go version
go version go1.21.3 windows/amd64
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;安装go插件&quot;&gt;安装go插件&lt;/h2&gt;

&lt;p&gt;VS code搜索go，第一个&lt;/p&gt;

&lt;h2 id=&quot;设置代理&quot;&gt;设置代理&lt;/h2&gt;

&lt;p&gt;cmd输入以下命令&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;go modules功能的开关是GO111MODULE&lt;/p&gt;

&lt;p&gt;https://goproxy.cn是国内代理&lt;/p&gt;

&lt;p&gt;在使用go modules时，GOPATH是无意义的&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The “gopls” command is not available. Run “go install -v golang.org/x/tools/gopls@latest” to install.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;下载依赖&quot;&gt;下载依赖&lt;/h2&gt;

&lt;p&gt;VS中ctrl shift p搜索go install/update tools&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ctrl K T 选择VSC主题&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;下载所有依赖&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/lanyily/Cplusplus-pic/main/2023/202310112035245.png&quot; alt=&quot;image-20231011203513207&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;go-modules依赖管理&quot;&gt;go modules依赖管理&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;go mod tidy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;将当前源码文件所依赖的包安装，多的删掉，少了补上&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;go mod init 应用名称(项目名称)  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;执行该命令，会在应用过的根目录下(家目录)，生成go.mod文件。&lt;/p&gt;

&lt;p&gt;我们在进行go语言项目开发的时候，会依赖3种类型的库包：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;内置的标准库包，在goroot/src目录下，也就是我们安装目录的src目录下(类似于python的bin目录)&lt;/li&gt;
  &lt;li&gt;第三方库包（git上开源的）&lt;/li&gt;
  &lt;li&gt;项目中的库包，也就是项目中的其他目录。自己调用自己写的函数方法&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;调试&quot;&gt;调试&lt;/h2&gt;

&lt;p&gt;文件目录&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/lanyily/Cplusplus-pic/main/2023/202310112110050.png&quot; alt=&quot;image-20231011211014017&quot; /&gt;&lt;/p&gt;

&lt;p&gt;打断点&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/lanyily/Cplusplus-pic/main/2023/202310112109056.png&quot; alt=&quot;image-20231011210923999&quot; /&gt;&lt;/p&gt;</content><author><name>Ge Lei</name><email>&lt;mail@domain.tld&gt;</email></author><category term="golang" /><summary type="html">windows系统，使用vs code作为IDE，配置golang环境</summary></entry><entry><title type="html">简单工厂模式</title><link href="https://lanyily.github.io/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/2023-09-22-design-pattern/" rel="alternate" type="text/html" title="简单工厂模式" /><published>2023-09-22T00:00:00+00:00</published><updated>2023-09-22T00:00:00+00:00</updated><id>https://lanyily.github.io/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/design-pattern</id><content type="html" xml:base="https://lanyily.github.io/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/2023-09-22-design-pattern/">&lt;p&gt;定义一个工厂类，其成员函数可以根据不同的参数创建并返回不同的类对象，调用者无需关注创建细节&lt;/p&gt;

&lt;h2 id=&quot;简介&quot;&gt;简介&lt;/h2&gt;

&lt;p&gt;模式：简单工厂&lt;/p&gt;

&lt;p&gt;英文：simple factory&lt;/p&gt;

&lt;p&gt;定义：定义一个工厂类，其成员函数可以根据不同的参数创建并返回不同的类对象，调用者无需关注创建细节&lt;/p&gt;

&lt;p&gt;意图：实例化的活动不应该总是公开地进行，为了避免初始化总是造成耦合问题，将两者解耦&lt;/p&gt;

&lt;h2 id=&quot;设计准则&quot;&gt;设计准则&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;&lt;em&gt;对修改关闭，对扩展开放&lt;/em&gt;&lt;/strong&gt;：增加新功能不应该修改已经存在的代码，而应该通过增加新类或新成员函数&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;em&gt;针对接口编程，不针对实现编程&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;em&gt;依赖倒置原则：要依赖抽象，不要依赖具体类&lt;/em&gt;&lt;/strong&gt;：不能让高层组件依赖低层组件，而且两者都应该依赖于抽象&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;em&gt;封装变化&lt;/em&gt;&lt;/strong&gt;：将容易变化的代码段限制在一个小范围内&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;代码&quot;&gt;代码&lt;/h2&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;iostream&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Role&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;life&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_life&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;life&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){}&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;protected:&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_life&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;R_A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;R_A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;life&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;life&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;创建A角色&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;R_B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;R_B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;life&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;life&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;创建B角色&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;R_C&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;R_C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;life&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;life&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;创建C角色&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoleFactory&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createRole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;roletype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_Role&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;roletype&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;p_Role&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R_A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;roletype&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;C&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;p_Role&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R_C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;roletype&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;p_Role&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R_B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_Role&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;RoleFactory&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rolefactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_role1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rolefactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createRole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_role2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rolefactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createRole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;C&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_role3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rolefactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createRole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_role1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_role2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_role3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;由于创建角色与角色工厂本身无关，所以可以使用static方法，也就是是静态工厂方法模式&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C++&quot;&gt;#include &amp;lt;iostream&amp;gt;
class Role {
public:
	Role(int life, int magic, int attack) :m_life(life), m_magic(magic), m_attack(attack) {}
	virtual ~Role() {}
protected:
	int m_life;
	int m_magic;
	int m_attack;
};

class R_A :public Role {
public:
	R_A(int life, int magic, int attack) :Role(life, magic, attack)
	{
		std::cout &amp;lt;&amp;lt; &quot;创建A角色&quot; &amp;lt;&amp;lt; std::endl;
	}
};
class R_B :public Role {
public:
	R_B(int life, int magic, int attack) :Role(life, magic, attack)
	{
		std::cout &amp;lt;&amp;lt; &quot;创建B角色&quot; &amp;lt;&amp;lt; std::endl;
	}
};
class R_C :public Role {
public:
	R_C(int life, int magic, int attack) :Role(life, magic, attack)
	{
		std::cout &amp;lt;&amp;lt; &quot;创建C角色&quot; &amp;lt;&amp;lt; std::endl;
	}
};
class RoleFactory
{
public:
	static Role* createRole(std::string roletype)
	{
		Role* p_Role = nullptr;
		if (roletype == &quot;A&quot;)
			p_Role = new R_A(300, 400, 1000);
		else if (roletype == &quot;C&quot;)
			p_Role = new R_C(1000, 400, 500);
		else if (roletype == &quot;B&quot;)
			p_Role = new R_B(400, 400, 800);
		return p_Role;
	}
};

int main() {
	Role* p_role1 = RoleFactory::createRole(&quot;A&quot;);
	Role* p_role2 = RoleFactory::createRole(&quot;C&quot;);
	Role* p_role3 = RoleFactory::createRole(&quot;B&quot;);
	delete p_role1;
	delete p_role2;
	delete p_role3;
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;缺点&quot;&gt;缺点&lt;/h2&gt;

&lt;p&gt;当引入新的子类时，需要修改createRole函数的源码，违背了开闭准则&lt;/p&gt;

&lt;h2 id=&quot;使用场景&quot;&gt;使用场景&lt;/h2&gt;

&lt;h2 id=&quot;相关模式&quot;&gt;相关模式&lt;/h2&gt;</content><author><name>Ge Lei</name><email>&lt;mail@domain.tld&gt;</email></author><category term="设计模式" /><summary type="html">定义一个工厂类，其成员函数可以根据不同的参数创建并返回不同的类对象，调用者无需关注创建细节</summary></entry><entry><title type="html">享元模式</title><link href="https://lanyily.github.io/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/2023-09-15-design-pattern/" rel="alternate" type="text/html" title="享元模式" /><published>2023-09-15T00:00:00+00:00</published><updated>2023-09-15T00:00:00+00:00</updated><id>https://lanyily.github.io/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/design-pattern</id><content type="html" xml:base="https://lanyily.github.io/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/2023-09-15-design-pattern/">&lt;p&gt;本文介绍享元模式&lt;/p&gt;

&lt;h2 id=&quot;简介&quot;&gt;简介&lt;/h2&gt;

&lt;p&gt;模式：享元模式&lt;/p&gt;

&lt;p&gt;英文：flyweight&lt;/p&gt;

&lt;p&gt;定义：使用共享技术有效地支持大量细粒度的对象的复用，从而到达使用大量相似对象的同样的效果。&lt;/p&gt;

&lt;p&gt;命名由来：flyweight是特轻量级，蝇量级的意思&lt;/p&gt;

&lt;p&gt;意图：在同类对象十分多的情况下，改变模式，当需要某个对象时，尽量共用已经创建出来的同类对象，从而避免频繁new，节约内存，提高效率。&lt;/p&gt;

&lt;h2 id=&quot;概念&quot;&gt;概念&lt;/h2&gt;

&lt;p&gt;享元：被共享的单元或者对象&lt;/p&gt;

&lt;p&gt;内部状态：存储在享元对象内部的，一直不会发生改变的状态，这种状态可以被共享，一般可以作为享元类的成员变量&lt;/p&gt;

&lt;p&gt;外部状态：随着外部环境改变而改变的状态，不可以被共享&lt;/p&gt;

&lt;p&gt;总之，将内部状态相同的对象存储在享元池中，传递不同的外部状态。确定内部状态的时候，需要将在多个地方共享的成员变量作为享元对象的内部状态&lt;/p&gt;

&lt;h3 id=&quot;享元池&quot;&gt;享元池&lt;/h3&gt;

&lt;p&gt;享元模式中使用了简单工厂，这个工厂一般用于创建享元对象，并保存在一个容器中，这个容器专门用于保存一个或者多个享元对象，称为享元池&lt;/p&gt;

&lt;p&gt;享元池的引入造成了程序的复杂性，需要衡量性价比&lt;/p&gt;

&lt;p&gt;享元池和对象池，连接池，线程池都可以看成是对象的复用，但是后三者强调储备量，比如线程池可以规定线程池中线程数最多为多少，但是享元池强调的是创建对象这个过程可以使用享元池中的已有一种对象进行代替&lt;/p&gt;

&lt;h2 id=&quot;代码结构&quot;&gt;代码结构&lt;/h2&gt;

&lt;p&gt;一般由以下几个部分组成&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;抽象享元类：Piece&lt;/li&gt;
  &lt;li&gt;具体享元类：BlackPiece，可以考虑使用单件模式实现&lt;/li&gt;
  &lt;li&gt;享元工厂类：pieceFactory，可以考虑使用单件模式实现&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;代码&quot;&gt;代码&lt;/h2&gt;

&lt;p&gt;使用享元模式前：&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;list&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumColor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Black&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;White&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Position&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmpx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Piece&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Piece&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EnumColor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmpcolor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Position&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmppos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpcolor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmppos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;private:&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;EnumColor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Position&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Piece&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Black&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;绘制黑棋于&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;,&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;绘制白棋于&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;,&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;Piece&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_piece1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Piece&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Black&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;p_piece1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;Piece&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_piece2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Piece&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;White&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;p_piece2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;Piece&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_piece3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Piece&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Black&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;p_piece3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Piece&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;piece_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;piece_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_piece1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;piece_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_piece2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;piece_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_piece3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_piece1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_piece2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_piece3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;使用享元模式后：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C++&quot;&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;list&amp;gt;
#include&amp;lt;map&amp;gt;
enum EnumColor {
	Black, White
};
struct Position {
	int m_x;
	int m_y;
	Position(int tmpx, int tmpy) :m_x(tmpx), m_y(tmpy) {}
};
class Piece
{
public:
	virtual ~Piece() {};
	virtual void draw(Position tmppos)=0;
};
class BlackPiece:public Piece {
public:
	virtual void draw(Position tmppos) {
		std::cout &amp;lt;&amp;lt; &quot;绘制黑棋于&quot; &amp;lt;&amp;lt; tmppos.m_x &amp;lt;&amp;lt; &quot;,&quot; &amp;lt;&amp;lt; tmppos.m_y &amp;lt;&amp;lt; std::endl;
	}
};
class WhitePiece :public Piece {
public:
	virtual void draw(Position tmppos) {
		std::cout &amp;lt;&amp;lt; &quot;绘制白棋于&quot; &amp;lt;&amp;lt; tmppos.m_x &amp;lt;&amp;lt; &quot;,&quot; &amp;lt;&amp;lt; tmppos.m_y &amp;lt;&amp;lt; std::endl;
	}
};
class pieceFactory {
public:
	~pieceFactory()
	{
		for (auto iter = m_FlyWeightMap.begin(); iter != m_FlyWeightMap.end(); iter++)
		{
			Piece* tmpfw = iter-&amp;gt;second;
			delete tmpfw;
		}
		m_FlyWeightMap.clear();
	}
	Piece* getFlyWeight(EnumColor tmpcolor)
	{
		auto iter = m_FlyWeightMap.find(tmpcolor);
		if(iter==m_FlyWeightMap.end())
		{
			Piece* tmpfw = nullptr;
			if (tmpcolor == Black) tmpfw = new BlackPiece();
			else tmpfw = new WhitePiece();
			m_FlyWeightMap.insert(std::make_pair(tmpcolor, tmpfw));
			return tmpfw;
		}
		else 
			return iter-&amp;gt;second;
	}
private:
	std::map&amp;lt;EnumColor, Piece*&amp;gt;m_FlyWeightMap;
};
int main()
{
	pieceFactory* pfactory = new pieceFactory();
	Piece* p_piece1 = pfactory-&amp;gt;getFlyWeight(Black);
	p_piece1-&amp;gt;draw(Position(3, 3));

	Piece* p_piece2 = pfactory-&amp;gt;getFlyWeight(Black);
	p_piece2-&amp;gt;draw(Position(5, 5));

	Piece* p_piece3 = pfactory-&amp;gt;getFlyWeight(Black);
	p_piece3-&amp;gt;draw(Position(4, 6));

	Piece* p_piece4 = pfactory-&amp;gt;getFlyWeight(Black);
	p_piece4-&amp;gt;draw(Position(5, 7));

	delete pfactory;
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;关闭命令行输出时两种代码创建相同数量的类的运行速度：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;对象数/ms&lt;/th&gt;
      &lt;th&gt;普通模式&lt;/th&gt;
      &lt;th&gt;享元模式&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1000（波动大）&lt;/td&gt;
      &lt;td&gt;400&lt;/td&gt;
      &lt;td&gt;170-356&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;一万&lt;/td&gt;
      &lt;td&gt;2572&lt;/td&gt;
      &lt;td&gt;1800-2200&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;十万&lt;/td&gt;
      &lt;td&gt;19643-33911&lt;/td&gt;
      &lt;td&gt;15749-16401&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;百万&lt;/td&gt;
      &lt;td&gt;249130-216128&lt;/td&gt;
      &lt;td&gt;159932&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;千万&lt;/td&gt;
      &lt;td&gt;2417764-2123181&lt;/td&gt;
      &lt;td&gt;1616665-1656742&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;一亿&lt;/td&gt;
      &lt;td&gt;19677707-20324193&lt;/td&gt;
      &lt;td&gt;15560363&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;可以看出来性能提升还不小，优化了25%左右&lt;/p&gt;

&lt;h2 id=&quot;使用场景&quot;&gt;使用场景&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;程序中有大量相同或者相似的对象造成内存的大量消耗&lt;/li&gt;
  &lt;li&gt;对象的大部分状态可以定义为外部状态作为参数传入&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;相关模式&quot;&gt;相关模式&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;简单工厂模式&lt;/li&gt;
  &lt;li&gt;单件模式&lt;/li&gt;
&lt;/ol&gt;</content><author><name>Ge Lei</name><email>&lt;mail@domain.tld&gt;</email></author><category term="设计模式" /><summary type="html">本文介绍享元模式</summary></entry><entry><title type="html">模版方法模式</title><link href="https://lanyily.github.io/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/2023-09-01-design-pattern/" rel="alternate" type="text/html" title="模版方法模式" /><published>2023-09-01T00:00:00+00:00</published><updated>2023-09-01T00:00:00+00:00</updated><id>https://lanyily.github.io/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/design-pattern</id><content type="html" xml:base="https://lanyily.github.io/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/2023-09-01-design-pattern/">&lt;p&gt;本文介绍模版方法模式&lt;/p&gt;

&lt;h2 id=&quot;简介&quot;&gt;简介&lt;/h2&gt;

&lt;p&gt;模式名：模版方法模式&lt;/p&gt;

&lt;p&gt;英文：template method&lt;/p&gt;

&lt;p&gt;定义：由固定步骤组成的事情，在步骤确定的情况下，通过多态在子类中对每步进行差异性实现。&lt;/p&gt;

&lt;p&gt;命名由来：某个成员方法，称为A，固定调用某几个成员方法，故称A为模版方法，这种方法叫做模版方法模式&lt;/p&gt;

&lt;p&gt;意图：定义一个操作的算法骨架，将一些步骤延迟到子类实现，通过父类定义虚函数，子类重写/实现来做到&lt;/p&gt;

&lt;h2 id=&quot;概念&quot;&gt;概念&lt;/h2&gt;

&lt;h3 id=&quot;早绑定与晚绑定&quot;&gt;早绑定与晚绑定&lt;/h3&gt;

&lt;p&gt;早绑定：编译阶段就知道代码调用的哪个类的方法&lt;/p&gt;

&lt;p&gt;晚绑定：父类指针指向子类对象，运行期间才能知道调用哪种方法&lt;/p&gt;

&lt;h3 id=&quot;钩子方法hook&quot;&gt;钩子方法hook&lt;/h3&gt;

&lt;p&gt;子类可以控制父类的行为的方法&lt;/p&gt;

&lt;h2 id=&quot;使用场景&quot;&gt;使用场景&lt;/h2&gt;

&lt;h3 id=&quot;mfc&quot;&gt;MFC&lt;/h3&gt;

&lt;p&gt;MFC创建对话框的应用程序&lt;/p&gt;

&lt;h3 id=&quot;车间&quot;&gt;车间&lt;/h3&gt;

&lt;p&gt;零件装配工序固定，则针对零件创建一个父类，零件装配工序采用模版方法模式来实现，处理某道工序的细节可以放在子类的虚函数中&lt;/p&gt;

&lt;h2 id=&quot;相关模式&quot;&gt;相关模式&lt;/h2&gt;</content><author><name>Ge Lei</name><email>&lt;mail@domain.tld&gt;</email></author><category term="设计模式" /><summary type="html">本文介绍模版方法模式</summary></entry></feed>