0%

Here's something encrypted, password is required to continue reading.
阅读全文 »

1 CSS

css是一种用来为结构化文档(如 HTML 文档或 XML 应用)添加样式(字体、间距和颜色等)的计算机语言,CSS 文件扩展名为 .css。通过使用 CSS 我们可以大大提升网页开发的工作效率!其语法如下:

  • 选择器通常是需要改变样式的 HTML 元素
  • 每条声明由一个属性和一个值组成。
  • CSS声明总是以分号 ; 结束,声明总以大括号 {} 括起来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<style>
p
{
color:red;
text-align:center;
}
</style>
</head>

<body>
<p>Hello World!</p>
<p>这个段落采用CSS样式化。</p>
</body>
</html>

css的注释是同c++的/* */

阅读全文 »

1 vue简介

Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面

Vue 是一个框架,也是一个生态。其功能覆盖了大部分前端开发常见的需求。但 Web 世界是十分多样化的,不同的开发者在 Web 上构建的东西可能在形式和规模上会有很大的不同。考虑到这一点,Vue 的设计非常注重灵活性和“可以被逐步集成”这个特点。根据你的需求场景,你可以用不同的方式使用 Vue:

  • 无需构建步骤,渐进式增强静态的 HTML
  • 在任何页面中作为 Web Components 嵌入
  • 单页应用 (SPA)
  • 全栈 / 服务端渲染 (SSR)
  • Jamstack / 静态站点生成 (SSG)
  • 开发桌面端、移动端、WebGL,甚至是命令行终端中的界面
阅读全文 »

1 Django 简介

1.1 基本介绍

Django 是一个高级的 Python Web 框架,用于快速开发可维护和可扩展的 Web 应用程序。

使用 Django,只要很少的代码,Python 的程序开发人员就可以轻松地完成一个正式网站所需要的大部分内容,并进一步开发出全功能的 Web 服务。

Django 本身基于 MVC 模型,即 Model(模型)+ View(视图)+ Controller(控制器)设计模式,MVC 模式使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。

Django想要理解,首先要明白的就是Django的大致组成,它大致由四部分组成,也就是提到的MTV模型:

  • Model(模型):负责业务对象与数据库的对象(orm)

  • Template(模板):负责把数据展示给用户(前端的东西)

  • View(视图):负责业务逻辑,并在适当的时候会调用Model和Template

  • URL分发器:通过前台请求的url,来分配调到相应的函数操作,类似于网络中的路由表,控制网络的下一跳的地址。

阅读全文 »

1 什么是OpenTelemtry

OpenTelemetry,也称为 OTel,是一个供应商中立的开源可观测性框架 用于检测、生成、收集和导出遥测数据,例如跟踪(trace)、指标(metric)和日志(log)等signal(信号)。OpenTelemetry 是一个可观测性框架和工具包,旨在创建和管理遥测数据,例如跟踪、指标和日志。至关重要的是,OpenTelemetry 是供应商和 与工具无关,这意味着它可以与各种可观测性一起使用

1.1 什么是可观测性?

可观测性是指通过检查系统的内部输出来了解系统内部状态的能力。在软件的上下文中,这意味着能够理解 通过检查系统的遥测数据来检查系统的内部状态,其中遥测数据包括跟踪、指标和日志

要使系统可观察,必须对其进行检测。也就是说,代码必须发出跟踪、指标或日志。然后,必须将检测的数据发送到可观测性后端

阅读全文 »

什么是虚拟化(VMVARE的实现原理是什么,为什么能够在一个系统上虚拟化实现另一个系统?)

VMware是一款强大的虚拟化软件,它能够在一个物理服务器上创建并运行多个虚拟机,每个虚拟机都像是独立的计算机系统,拥有自己的操作系统和应用程序。VMware实现虚拟化的原理主要基于以下几个关键组件和技术:

  • 虚拟机监视器(Hypervisor):VMware通过在物理服务器上安装虚拟机监视器(也被称为VMM或Hypervisor)来实现虚拟化。VMM是一个软件层,位于物理服务器和虚拟机之间,负责管理虚拟机的创建、启动、停止和运行。VMM能够抽象物理服务器的硬件资源,为虚拟机提供一个隔离的、安全的运行环境。

  • 资源隔离:VMM通过创建逻辑分区来将物理服务器的计算资源(如处理器、内存、存储等)分配给不同的虚拟机。每个虚拟机都在自己的逻辑环境中运行,与其他虚拟机相互隔离。这种隔离性确保了每个虚拟机都能够独立运行,互不影响,从而提供了更高的安全性和可靠性。

  • 资源共享:虚拟化平台利用资源池的概念,将物理服务器上的处理能力和存储容量整合在一起,然后动态地按需分配给虚拟机。这意味着物理资源可以根据虚拟机的需求进行灵活分配和调整,提高了资源的利用率和系统的灵活性。

  • 虚拟硬件:VMware虚拟化可以模拟多种虚拟硬件设备,包括处理器、内存、磁盘、网络接口等。每个虚拟机都认为自己拥有独立的硬件资源,可以在其内部安装操作系统和应用程序。这种模拟使得虚拟机能够像真实计算机一样运行各种软件和服务。

  • 内存和存储虚拟化:VMware使用内存分页技术将虚拟机的内存分成固定大小的页面,并映射到物理服务器的内存中。同时,它也将物理服务器的存储资源虚拟化为多个独立的虚拟存储设备,供虚拟机使用。

  • ** 迁移和克隆**:VMware还支持虚拟机的迁移和克隆操作,这意味着虚拟机可以在不同的物理服务器之间轻松迁移,或者创建虚拟机的副本以进行备份或扩展。

通过上述技术和组件的协同工作,VMware能够在单一系统上实现多个虚拟系统的运行。这种虚拟化技术不仅提高了硬件资源的利用率,还简化了系统的管理和维护,使得用户可以更加灵活和高效地部署和管理应用程序和服务。

1. go简述

1.1 为什么要创造一门编程语言

  • C/C++ 的发展速度无法跟上计算机发展的脚步,十多年来也没有出现一门与时代相符的主流系统编程语言,因此人们需要一门新的系统编程语言来弥补这个空缺,尤其是在计算机信息时代。
  • 相比计算机性能的提升,软件开发领域不被认为发展得足够快或者比硬件发展得更加成功(有许多项目均以失败告终),同时应用程序的体积始终在不断地扩大,这就迫切地需要一门具备更高层次概念的低级语言来突破现状。
  • 在 Go 语言出现之前,开发者们总是面临非常艰难的抉择,究竟是使用执行速度快但是编译速度并不理想的语言(如:C++),还是使用编译速度较快但执行效率不佳的语言(如:.NET、Java),或者说开发难度较低但执行速度一般的动态语言呢?显然,Go 语言在这 3 个条件之间做到了最佳的平衡:快速编译,高效执行,易于开发。

1.2 Go语言的发展目标

  • Go 语言的主要目标是将静态语言的安全性和高效性(C++)与动态语言的易开发性(python)进行有机结合,达到完美平衡,从而使编程变得更加有乐趣,而不是在艰难抉择中痛苦前行。

因此,Go 语言是一门类型安全和内存安全的编程语言。虽然 Go 语言中仍有指针的存在,但并不允许进行指针运算。

  • Go 语言的另一个目标是对于网络通信、并发和并行编程的极佳支持,从而更好地利用大量的分布式和多核的计算机,这一点对于谷歌内部的使用来说就非常重要了。设计者通过** goroutine** 这种轻量级线程的概念来实现这个目标,然后通过** channel **来实现各个 goroutine 之间的通信。他们实现了分段栈增长和 goroutine 在线程基础上多路复用技术的自动化。

这个特性显然是 Go 语言最强有力的部分,不仅支持了日益重要的多核与多处理器计算机,也弥补了现存编程语言在这方面所存在的不足。

  • Go 语言中另一个非常重要的特性就是它的构建速度(编译和链接到机器代码的速度),一般情况下构建一个程序的时间只需要数百毫秒到几秒。作为大量使用C++ 来构建基础设施的谷歌来说,无疑从根本上摆脱了 C++ 在构建速度上非常不理想的噩梦。这不仅极大地提升了开发者的生产力,同时也使得软件开发过程中的代码测试环节更加紧凑,而不必浪费大量的时间在等待程序的构建上。

依赖管理是现今软件开发的一个重要组成部分,但是 C 语言中“头文件”的概念却导致越来越多因为依赖关系而使得构建一个大型的项目需要长达几个小时的时间。人们越来越需要一门具有严格的、简洁的依赖关系分析系统从而能够快速编译的编程语言。这正是 Go 语言采用包模型的根本原因,这个模型通过严格的依赖关系检查机制来加快程序构建的速度,提供了非常好的可量测性。

整个 Go 语言标准库的编译时间一般都在** 20 **秒以内,其它的常规项目也只需要半秒钟的时间来完成编译工作。这种闪电般的编译速度甚至比编译 C 语言或者 Fortran 更加快,使得编译这一环节不再成为在软件开发中困扰开发人员的问题。在这之前,动态语言将快速编译作为自身的一大亮点,像C++那样的静态语言一般都有非常漫长的编译和链接工作。而同样作为静态语言的 Go 语言,通过自身优良的构建机制,成功地去除了这个弊端,使得程序的构建过程变得微不足道,拥有了像脚本语言和动态语言那样的高效开发的能力。

  • 另外,Go 语言在执行速度方面也可以与 C/C++ 相提并论。

  • 由于内存问题(通常称为内存泄漏)长期以来一直伴随着 C++ 的开发者们,Go 语言的设计者们认为内存管理不应该是开发人员所需要考虑的问题。因此尽管 Go 语言像其它静态语言一样执行本地代码,但它依旧运行在某种意义上的虚拟机,以此来实现高效快速的垃圾回收(使用了一个简单的标记-清除算法)。

尽管垃圾回收并不容易实现,但考虑这将是未来并发应用程序发展的一个重要组成部分,Go 语言的设计者们还是完成了这项艰难的任务。

  • Go 语言还能够在运行时进行反射相关的操作。

  • 使用 go install 能够很轻松地对第三方包进行部署。

  • 此外,Go 语言还支持调用由 C 语言编写的海量库文件(第 3.9 节),从而能够将过去开发的软件进行快速迁移。

1.3 语言的特性

Go 语言从本质上(程序和结构方面)来实现并发编程。

因为 Go 语言没有类和继承的概念,所以它和 Java 或 C++ 看起来并不相同。但是它通过接口 (interface) 的概念来实现多态性。Go 语言有一个清晰易懂的轻量级类型系统,在类型之间也没有层级之说。因此可以说这是一门混合型的语言。

Go 语言使用静态类型,所以它是类型安全的一门语言,加上通过构建到本地代码,程序的执行速度也非常快。

作为强类型语言隐式的类型转换是不被允许的,记住一条原则:让所有的东西都是显式的。

Go 语言其实也有一些动态语言的特性(通过关键字 var),所以它对那些逃离 Java 和 .Net 世界而使用 Python、Ruby、PHP 和 JavaScript 的开发者们也具有很大的吸引力。

Go 语言支持交叉编译,比如说你可以在运行 Linux 系统的计算机上开发运行 Windows 下运行的应用程序。这是第一门完全支持 UTF-8 的编程语言,这不仅体现在它可以处理使用 UTF-8 编码的字符串,就连它的源码文件格式都是使用的 UTF-8 编码。Go 语言做到了真正的国际化!

1.4 相关特性的缺失

许多能够在大多数面向对象语言中使用的特性 Go 语言都没有支持,但其中的一部分可能会在未来被支持。

  • 为了简化设计,不支持函数重载和操作符重载
  • 为了避免在 C/C++ 开发中的一些 Bug 和混乱,不支持隐式转换
  • Go 语言通过另一种途径实现面向对象设计(第 10-11 章)来放弃类和类型的继承
  • 尽管在接口的使用方面(第 11 章)可以实现类似变体类型的功能,但本身不支持变体类型
  • 不支持动态加载代码
  • 不支持动态链接库
  • 不支持泛型
  • 通过 recover() 和 panic() 来替代异常机制(第 13.2-13.3 节)
  • 不支持静态变量

1.5 Linux上安装go

  • 首先进入go官网下载指定的已编译好的源码包(ps:这里我的电脑是x86-64架构所以选择了`go1.22.1.linux-amd64.tar.gz,将其下载下来
    1
    wget https://golang.google.cn/dl/go1.22.1.linux-amd64.tar.gz
  • 解压缩到指定路径
    1
    tar  -C /usr/lib/go/ -xvf go1.22.1.linux-amd64.tar.gz
  • 建立软连接(可选)

    1
    ln -s /usr/lib/go/bin/go /usr/bin/go

  • 之后我们需要能够让Linux能够找到go这个编译器,所以需要配置~/.bashrc文件

    1
    2
    3
    export GOROOT=/usr/lib/go
    export GOPATH=$PATH:$GOROOT/bin
    export PATH=$PATH:/usr/bin

2 Go项目搭建先识

2.1 Go的25个关键字和36个预定义标识符

Go语言的关键字保留很少,只有25个,之所以刻意地将 Go 代码中的关键字保持的这么少,是为了简化在编译过程第一步中的代码解:

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

除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符,其中包含了基本类型的名称和一些基本的内置函数(第 6.5 节),它们的作用都将在接下来的章节中进行进一步地讲解。

append bool byte cap close complex complex64 complex128 uint16
copy false float32 float64 imag int int8 int16 uint32
int32 int64 iota len make new nil panic uint64
print println real recover string true uint uint8 uintptr

2.2 包的概念、导入与可见性

是结构化代码的一种方式:每个程序都由包(通常简称为 pkg)的概念组成,可以使用自身的包或者从其它包中导入内容。

一个包可以由许多以 .go 为扩展名的源文件组成,因此文件名和包名一般来说都是不相同的。必须源文件中非注释的第一行指明这个文件属于哪个

1
package main
一个应用程序可以包含不同的包,而且即使你只使用 main 包也不必把所有的代码都写在一个巨大的文件里:你可以用一些较小的文件,并且在每个文件非注释的第一行都使用 package main 来指明这些文件都属于 main 包。如果你打算编译包名不是为 main 的源文件,如 pack1,编译后产生的对象文件将会是 pack1.a 而不是可执行程序。另外要注意的是,所有的包名都应该使用小写字母。

如果想要构建一个程序,则包和包内的文件都必须以正确的顺序进行编译。包的依赖关系决定了其构建顺序。

属于同一个包的源文件必须全部被一起编译,一个包即是编译时的一个单元,因此根据惯例,项目的每个目录都建议只包含一个包。

如果对一个包进行更改或重新编译,所有引用了这个包的客户端程序都必须全部重新编译。

Go 中的包模型采用了显式依赖关系的机制来达到快速编译的目的,编译器会从后缀名为 .o 的对象文件(需要且只需要这个文件)中提取传递依赖类型的信息。

如果 A.go 依赖 B.go,而B.go又依赖 C.go

  • 编译 C.go, B.go, 然后是 A.go.
  • 为了编译 A.go, 编译器读取的是 B.o 而不是 C.o.

这种机制对于编译大型的项目时可以显著地提升编译速度。每一段代码只会被编译一次

2.2.1 包的导入

包的导入使用import,下面使用因式分解关键字导入包

1
2
3
4
import (
"fmt"
"os"
)
>当你导入多个包时,最好按照字母顺序排列包名,这样做更加清晰易读。

2.2.2 可见性规则

当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是它们在整个包的内部是可见并且可用的(像面向对象语言中的 private )。

因此,在导入一个外部包后,能够且只能够访问该包中导出的对象。

假设在包 pack1 中我们有一个变量或函数叫做Thing(以 T 开头,所以它能够被导出),那么在当前包中导入pack1包,Thing 就可以像面向对象语言那样使用点标记来调用:pack1.Thing(pack1 在这里是不可以省略的)。

1
2
3
import pack1

pack1.Thing()

如果你导入了一个包却没有使用它,则会在构建程序时引发错误,如imported and not used: xx,这正是遵循了 Go 的格言:“没有不必要的代码!”。

2.3 函数

  • 这是定义一个函数最简单的格式

    1
    func functionName()
    你可以在括号 () 中写入 0 个或多个函数的参数(使用逗号 , 分隔),每个参数的名称后面必须紧跟着该参数的类型。

  • main() 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。如果你的 main 包的源代码没有包含 main() 函数,则会引发构建错误 undefined: main.main

    go中的main() 函数既没有参数,也没有返回类型(与 C 家族中的其它语言恰好相反)。如果你不小心为 main() 函数添加了参数或者返回类型,将会引发构建错误:

    1
    func main must have no arguments and no return values results.

  • go的函数体必须使用大括号 {} 括起来。,而且左大括号{ 必须与方法的声明放在同一行,这是编译器的强制规定,否则你在使用 gofmt 时就会出现错误提示:

    1
    build-error: syntax error: unexpected semicolon or newline before {
    >(这是因为编译器会产生 func main() ; 这样的结果,很明显这是错误的) > >究其原因是因为:Go 语言虽然看起来不使用分号作为语句的结束,但实际上这一过程是由编译器自动完成,因此才会引发像上面这样的错误

  • 符合规范的函数一般写成如下的形式:
    1
    2
    3
    func functionName(parameter_list) (return_value_list) {

    }
    • parameter_list 的形式为 (param1 type1, param2 type2, …)
    • return_value_list 的形式为 (ret1 type1, ret2 type2, …)

一个函数可以拥有多返回值,返回类型之间需要使用逗号分割,并使用小括号 () 将它们括起来,如:

2.4 注释

go中的注释沿用了c/c++的注释风格,并且在此基础上提供了一个命令godoc,该命令从** Go 程序和包文件中提取顶级声明的首行注释以及每个对象的相关注释,并生成相关文档。**

一般用法

  • go doc package 获取包的文档注释,例如:go doc fmt 会显示使用 godoc 生成的 fmt 包的文档注释。
  • go doc package/subpackage 获取子包的文档注释,例如:go doc container/list。
  • go doc package function 获取某个函数在某个包中的文档注释,例如:go doc fmt Printf 会显示有关 fmt.Printf() 的使用说明。

这个工具只能获取在 Go 安装目录下 ../go/src 中的注释内容。此外,它还可以作为一个本地文档浏览 web 服务器。在命令行输入 godoc -http=:6060,然后使用浏览器打开 http://localhost:6060 后,你就可以看到本地文档浏览服务器提供的页面。

2.5 类型

使用 var 声明的变量的值会自动初始化为该类型的零值。类型定义了某个变量的值的集合与可对其进行操作的集合。

  • 类型可以是基本类型,如:int、float、bool、string;
  • 结构化的(复合的),如:struct、array、切片 (slice)、map、通道 (channel);
  • 只描述类型的行为的,如:interface。

结构化的类型没有真正的值,它使用 nil作为默认值(在 Objective-C 中是 nil,在 Java 中是 null,在 C 和 C++ 中是 NULL 或 0)。值得注意的是,Go 语言中不存在类型继承

函数也可以是一个确定的类型,就是以函数作为返回类型。这种类型的声明要写在函数名和可选的参数列表之后

1
2
//返回一个typeFunc类型的函数类型
func FunctionName (a typea, b typeb) typeFunc
你可以在函数体中的某处返回使用类型为 typeFunc 的变量 ret返回:
1
return var

使用 type 关键字可以定义你自己的类型,你可能想要定义一个结构体(第 10 章),但是也可以定义一个已经存在的类型的别名,如:

1
type IZ int
如果你有多个类型需要定义,可以使用因式分解关键字的方式,例如:
1
2
3
4
5
type (
IZ int
FZ float64
STR string
)

2.6 Go 程序的一般结构

go的编写结构:

  • 在完成包的 import 之后,开始对常量、变量和类型的定义或声明。
  • 如果存在 init() 函数的话,则对该函数进行定义(这是一个特殊的函数,每个含有该函数的包都会首先执行这个函数)。
  • 如果当前包是 main 包,则定义 main() 函数。
  • 然后定义其余的函数,首先是类型的方法,接着是按照main()函数中先后调用的顺序来定义相关函数,如果有很多函数,则可以按照字母顺序来进行排序。

Go 程序的执行(程序启动)顺序如下:

  • 按顺序导入所有被 main 包引用的其它包,然后在每个包中执行如下流程:
  • 如果该包又导入了其它的包,则从第一步开始递归执行,但是每个包只会被导入一次。
  • 然后以相反的顺序在每个包中初始化常量和变量,如果该包含有 init() 函数的话,则调用该函数。
  • 在完成这一切之后,main 也执行同样的过程,最后调用 main() 函数开始执行程序。

2.7 类型转换

在必要以及可行的情况下,一个类型的值可以被转换成另一种类型的值。由于 Go 语言不存在隐式类型转换,因此所有的转换都必须显式说明,就像调用一个函数一样(类型在这里的作用可以看作是一种函数):

1
valueOfTypeB = typeB(valueOfTypeA)
当编译器捕捉到非法的类型转换时会引发编译时错误,否则将引发运行时错误。同样的一个取值范围较大的转换到取值范围较小的类型时会产生精度丢失问题

2.8 常量

常量使用关键字 const 定义,用于存储不会改变的数据。存储在常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。常量的定义格式:const identifier [type] = value,例如:

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

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

但是这种隐式定义必须是能够在编译时就能够确定的;你可以在其赋值表达式中涉及计算过程,但是所有用于计算的值必须在编译期间就能获得,否则就会出错

1
2
3
4
正确的做法:
const c1 = 2/3
错误的做法:
const c2 = getNumber() // 引发构建错误: getNumber() used as value
因为在编译期间自定义函数均属于未知,因此无法用于常量的赋值,但内置函数可以使用,如:len()。

  • 常量可以并行赋值
    1
    2
    3
    4
    5
    6
    const beef, two, c = "eat", 2, "veg"
    const Monday, Tuesday, Wednesday, Thursday, Friday, Saturday = 1, 2, 3, 4, 5, 6
    const (
    Monday, Tuesday, Wednesday = 1, 2, 3
    Thursday, Friday, Saturday = 4, 5, 6
    )
  • 常量还可以用作枚举
    1
    2
    3
    4
    5
    const (
    Unknown = 0
    Female = 1
    Male = 2
    )

2.9 变量

声明变量的一般形式是使用var关键字:var identifier type

Go 和许多编程语言不同,它在声明变量时将变量的类型放在变量的名称之后。Go 为什么要选择这么做呢?

  • 首先,它是为了避免像 C 语言中那样含糊不清的声明形式,例如:int* a, b;。在这个例子中,只有 a 是指针而 b 不是。如果你想要这两个变量都是指针,则需要将它们分开书写。而在 Go 中,则可以很轻松地将它们都声明为指针类型

    1
    var a, b *int

  • 其次,这种语法能够按照从左至右的顺序阅读,使得代码更加容易理解。

    1
    2
    3
    var a int
    var b bool
    var str string

Go 编译器的智商已经高到可以根据变量的值来自动推断其类型,这有点像 Ruby 和 Python 这类动态语言,只不过它们是在运行时进行推断,而 Go 是在编译时就已经完成推断过程。因此,你还可以省略type使用下面的这些形式来声明及初始化变量:

1
2
3
var a = 15
var b = false
var str = "Go says hello to the world!"

2.9.1 值类型和引用类型

在go中的引用类型不同于C++中的引用定义,在 Go 语言中,指针属于引用类型,其它的引用类型还包括 slices(第 7 章),maps(第 8 章)和 channel(第 13 章)。被引用的变量会存储在堆中,以便进行垃圾回收,且比栈拥有更大的内存空间。。另一方面:

  • 像值类型的变量,go将它们存储在栈中
  • 对于引用类型,其存储在堆中,以便进行垃圾回收

2.9.2 :=初始化声明操作符

我们知道可以在变量的初始化时省略变量的类型而由系统自动推断,因此有什么我们对一个变量直接做初始化,此时var关键句就显得多余了。所以当我么声明初始化一个变量的时候可以使用:=初始化声明操作符

1
a,b:=50,false
- :=不允许对以及声明过的变量使用,换一句话就是说:=只允许声明事初始化 - :=只允许对局部变量使用,不允许对全局变量进行声明赋值

2.10 init()函数

变量除了可以在全局声明中初始化,也可以在 init() 函数中初始化。这是一类非常特殊的函数,它不能够被人为调用,而是在每个包完成初始化后自动执行,并且执行优先级比 main() 函数高。

每个源文件可以包含多个 init() 函数,同一个源文件中的 init() 函数会按照从上到下的顺序执行,如果一个包有多个源文件包含 init() 函数的话,则官方鼓励但不保证以文件名的顺序调用。初始化总是以单线程并且按照包的依赖关系顺序执行。

一个可能的用途是在开始执行程序之前对数据进行检验或修复,以保证程序状态的正确性。

3. 基本类型和运算符

go中的基本类型与C++差不多,都有布尔型bool、数字型(int和float32/64)和字符型(byte)。Go 语言支持整型和浮点型数字,并且原生支持复数,其中位的运算采用补码。

Go 也有基于架构的类型,例如:int、uint 和 uintptr。这些类型的长度都是根据运行程序所在的操作系统类型所决定的:

  • int 和 uint 在 32 位操作系统上,它们均使用 32 位(4 个字节),在 64 位操作系统上,它们均使用 64 位(8 个字节)。
  • uintptr 的长度被设定为足够存放一个指针即可。

Go 语言中没有 float 类型。(Go语言中只有 float32 和 float64)没有 double 类型。

3.1 复数类型

这里值得一提的是go引入的复数complex。Go 拥有以下复数类型

1
2
complex64 (32 位实数和虚数)
complex128 (64 位实数和虚数)
复数使用 re+imI 来表示,其中 re 代表实数部分,im 代表虚数部分,I 代表根号负 1。
1
2
3
4
fvar c1 complex64 = 5 + 10i
//在使用格式化说明符时,可以使用 %v 来表示复数,但当你希望只表示其中的一个部分的时候需要使用 %f
fmt.Printf("The value is: %v", c1)
// 输出: 5 + 10i
如果 re 和 im 的类型均为 float32,那么类型为 complex64 的复数 c 可以通过以下方式来获得:
1
c = complex(re, im)
此外,函数 real(c)imag(c) 可以分别获得相应的实数和虚数部分。

复数支持和其它数字类型一样的运算。当你使用等号 == 或者不等号 != 对复数进行比较运算时,注意对精确度的把握。cmath 包中包含了一些操作复数的公共方法。如果你对内存的要求不是特别高,最好使用 complex128 作为计算类型,因为相关函数都使用这个类型的参数。

3.2 随机数

一些像游戏或者统计学类的应用需要用到随机数。math/rand 包实现了伪随机数的生成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main
import (
"fmt"
"math/rand"
"time"
)

func main() {
for i := 0; i < 10; i++ {
a := rand.Int() //随机生成Int范围随机数
fmt.Printf("%d / ", a)
}
for i := 0; i < 5; i++ {
r := rand.Intn(8) //随机生成[0,8)随机数
fmt.Printf("%d / ", r)
}
fmt.Println()
timens := int64(time.Now().Nanosecond())
rand.Seed(timens) //随机数种子
for i := 0; i < 10; i++ {
fmt.Printf("%2.2f / ", 100*rand.Float32())
}
}
函数 rand.Float32 和 rand.Float64 返回介于[0.0,1.0)之间的伪随机数,其中包括 0.0 但不包括 1.0。函数 rand.Intn 返回介于[0,n)之间的伪随机数。

你可以使用 rand.Seed(value) 函数来提供伪随机数的生成种子,一般情况下都会使用当前时间的纳秒级数字

3.3 字符类型

严格来说,字符类型并不是 Go 语言的一个类型,字符只是整数的特殊用例。byte 类型是 uint8 的别名,对于只占用 1 个字节的传统 ASCII 编码的字符来说,完全没有问题。例如:var ch byte = 'A';字符使用单引号括起来。

在 ASCII 码表中,'A' 的值是 65,而使用 16 进制表示则为 41,所以下面的写法是等效的:

1
2
//`\x`是十六进制表示法
var ch byte = 65var ch byte = '\x41'
另外一种可能的写法是\后面紧跟着长度为 3 的 八进制数,例如:\377。

不过 Go 同样支持 Unicode(UTF-8),因此字符同样称为 Unicode 代码点或者 runes,并在内存中使用 int 来表示。在文档中,一般使用格式 U+hhhh 来表示,其中 h 表示一个 16 进制数。其实 rune 也是 Go 当中的一个类型,并且是 int32 的别名。

在书写 Unicode 字符时,需要在 16 进制数之前加上前缀

1. 分布式和集群的区别是什么?

  • 分布式:侧重于将任务分拆多个子任务,部署在不同的服务器上,解决计算能力的问题
  • 集群:侧重同一个业务,部署在多个服务器上,提高系统可用性和性能。

分布式是一个为了解决单个物理服务器容量和性能瓶颈问题而采用的优化手段。它的核心概念是将一个业务拆分成不同的子业务,并部署在不同的机器上执行,服务之间通过远程调用协同工作,对外提供服务。这种拆分和部署的方式可以大大提高系统的可扩展性、可靠性和性能。

分布式涉及多个技术领域,包括但不限于分布式计算、分布式存储、分布式数据库、分布式文件系统等。这些技术各自有不同的应用场景和优势,如分布式计算可以处理巨量的数据和复杂的计算任务,分布式存储可以实现数据的高可用性和容错性,分布式数据库可以支持大规模并发访问和数据处理等。

阅读全文 »

Here's something encrypted, password is required to continue reading.
阅读全文 »

Cmake

CMake是很多项目首选的项目构建工具。其次,目前很多开发工具,比如VSCode,Clion都支持使用CMake构建项目。使用Cmake能够更加方便的用一个文件实现对C/C++项目的维护管理。

阅读全文 »