看一下.NET开发人员的眼光。 第一周

大家好!

我叫Lex,是YouTube频道“ IT Beard ”的主持人。 我是6岁的员工。 最近,我渴望超越核心技术(C#/。NET),并了解Blob悖论的本质。 我坚决决定要尝试使用另一种语言,而偶然的选择落在了Go上。

为了以结构化的方式获取知识,我从mail.ru注册了一个课程,您可以在这里找到: https : //www.coursera.org/learn/golang-webservices-1 。 实际上,我将从本课程培训的第一周中学到的知识将进一步讨论。 走吧


我将从语言的小介绍开始。 Go在多核处理器(2007-2009)时就已经开发出来了,因此这里的跨核并行工作一切都很好。 此外,该语言还可以很好地满足竞争(同时)要求。 通常,可以找到各种Web服务和已加载的Web系统。 这正是我所需要的,因为近年来我一直在开发Web api(Web API)。

开始


要使用该语言,只需安装大小为118mb 的“ Go工具”软件包 ,即可开始编码。

这些脚本具有* .go扩展名 ,并通过命令行上的go命令运行(我是Windows命令行的遵循者)。 gofmt命令放置所有缩进空间,并从文件中提取糖果(开箱即用代码美化器)。 就像在我最喜欢的子网中一样,在Go中,程序执行从main方法开始。
一项很酷的功能立即引起了我的注意- 您不能在行尾加分号 :)

Go是另一种语言(以及python,c#,php,js,ts和其他语言),在VSCode中使用起来很方便。 VSCode本身在编写代码时提供了绝对必要的所有软件包和依赖项。 保存IDE时,请为您运行gofmt并使代码更漂亮。

变数


这里的一切都很熟悉:有很多不同的类型,有默认值。 对于捐助者而言, var关键字表示不寻常,它意味着变量会更进一步,并且可以在变量名称之后声明或不声明变量的类型。 异常地。

通常,有很多方法可以声明和初始化变量。 您甚至可以在同一行上为多个变量(用逗号分隔)分配值。 顺便说一句,没有隐式强制转换。

Go还具有一个“ := ”运算符,该运算符使您可以声明并立即初始化新的(几乎总是只有新的)变量。 嗨帕斯卡;)

记录视图:

perem1, perem2 := 2, 3 
要么创建两个新变量,要么创建其中一个变量,而第二个变量只是分配一个新值。 这就是说,如果两个变量都已经存在,那么这将不起作用,并且您会得到一个错误,他们说使用常规分配。 运算符:=必须创建一些东西:)

还有一个有趣的假冒品-下划线字符“ _”。 这意味着没有变量,诸如此类:) (在实际情况中,这也是尖锐的,它也是: https : //docs.microsoft.com/zh-cn/dotnet/csharp/discards

图片

字符串带来的乐趣:字符串len(str)的字符串长度的标准计数以字节为单位 ,而在UTF8中,字符的重量可能更大。 要计算称为符文的字符,您需要使用“ utf8”包中的utf8.RuneCountInString(str)方法。 而且,而且-我们不会更改线(就像您喜欢的线一样)。

常数


常量可以分批声明。 常量有一个有趣的类型,即-iota 。 我将其称为Jopta。 Jopta允许您基于其他常量来做一些常量,例如常量的迭代器(让人想起子网的收益 )。

但是,常量可能无法输入。 对于此类常量,编译器会在正确的时间决定它们的类型。 方便地,已经存在了。



指针


是的,是的! 这里有一些指点,但似乎并不可怕。 他们说他们没有编号,并且您不能通过在指针上加上偶数来获得下一个指针。 在这里,它就像一个变量,它存储到另一个变量的链接(到目前为止,我已经某种程度上理解了它)。

指针是通过“与”号或new(类型)方法指定的(获取指向类型的指针,而不是变量):



如果直接访问指针,则链接会更改。 如果通过运算符“ * ”,则位于指针后面的变量值(指向该变量)将发生变化。 总的来说,这还不是很清楚,但是他们说会更加清楚。

数组


数组大小是数据类型的一部分! 因此,不同维度的数组实际上是不同类型的数据,并且不兼容。



但是,如果数组是如此干燥且不可变(它们无法在运行时更改),则需要什么。 因此,我们提出了基于数组的切片 (切片)



切片具有长度容量 。 它让我想起了SQL中的nvarchar数据类型。 即 您可以为数组分配内存空间(内存分配),但可以在其中放置任何长度的数组(最大容量)。 简而言之,这很有趣,您需要习惯它。 为了方便使用切片,有各种方法,例如make(),append(),len(),cap(),当然还有其他方法。 从一个切片(切片),您可以略微获得一个子切片(切片切片)。 顺便说一句, append()扩展了切片容量。

如果子切片等于切片,则实际上它们将引用一个内存。 因此,一个切片中值的更改将导致第二切片中的值更改。 但是,如果其中一个通过append()扩展,则会分配新的内存。
简而言之,一切都与内存有关:)

映射,哈希表,关联数组


所有这些都是相同的。 Go具有用于快速键搜索的哈希表。 初始化如下:



您可以创建子表(“地图地图”等)。 (任何级别的嵌套,有点像)。 有一个默认值,它在不存在的键上返回。 它取自键类型(对于bool,则为false)。 要知道默认情况下是否已返回变量,即 缺少密钥-使用密钥来存在密钥(有趣的事情):



控制结构


有一个if-else。 比起Sharps稍微有趣,因为您可以将初始化条件用于if。

有一个案件。 无需设置休息时间,这是有区别的。 逻辑反转)如果您还希望检查以下条件,则需要编写fallthrough

有的。 并且所有都有循环。



使用迭代切片会更有趣(范围运算符):



即使是通过哈希映射,您也可以迭代(尽管顺序通常会有所不同,因为映射不是定向的):



对于类型字符串 范围,它遍历符文,而不是字节。

功能介绍


通过func关键字声明。 此外,再次将逻辑反转与子网进行比较-首先显示输入参数,然后显示返回值的类型(您可以立即将其命名)。

函数可以返回多个结果 ,就像子网中的 元组一样。

默认情况下,该函数返回的命名值将使用该类型的默认值进行初始化。

但是,您可以使变量函数具有无限数量的相同类型的输入参数(例如,子网中的param)。 然后,特定类型的切片进入了函数的输入。

函数可以具有名称,也可以没有名称-onymous 。 并且它们可以被调用,可以被分配给变量。 看起来像JavaScript。 您甚至可以根据功能创建类型! 可以将函数作为参数传递(从子网读取委托)

甚至有一个关闭 (哦,吓人)! 您可以从其外部的函数(在父函数中读取)中获取变量。 这些是馅饼。

您可以声明函数的延迟执行 。 通过defer关键字可以完成此操作。 即 延迟函数在声明它们的函数的末尾以与这些延迟函数的声明相反的顺序执行。 在这里 此外,当声明defer块时,会执行延迟函数的参数的初始化。 这很重要,特别是如果将另一个函数用作参数时,它将比您期望的更早执行!

死了! Go具有这样的功能-panic() 。 就像扔进去,但更糟。 该功能停止程序执行。 但是,由于可以在函数结束时以任何方式执行,即使是在发生紧急情况之后,也可以通过延迟处理该紧急情况。 然而-慌乱的是,这不是一个尝试。 更糟!

结构(对象附近)


据说Go不是一种OOP范例语言。 但是有些东西就像结构 。 如果您来自子网划分领域,那么您就会知道我们也有结构-这些是可以存储在堆栈(值类型)中的对象的映射。 在Go中,结构是执行类似对象之类的唯一方法。 我还不能谈论价值的类型,但是与结构交互的本质与详细的结构非常相似。

每个结构本质上是一个单独的类型,并且可以具有一组特定类型的属性(包括另一个结构的类型或函数的类型):



另外,在这里可以看到从子网直接继承对象的某种机制。 在上图中,“ 客户”结构与“ 人”结构嵌套在一起。 这意味着Person的所有字段都将在Account类型的变量中可用。 如果属性名称重合(在上面的示例Id中,Name ),则不会发生冲突,但是将使用更高字段的值:



方法


是的,不仅有对象的相似性,还有方法的相似性。 几乎是面向对象的:)方法是绑定到特定类型 (例如,结构)的函数 。 方法与声明中的函数不同:在func关键字之后,需要在方括号中指定此方法所属的类型以及传递此类型的变量的作用。 扮演什么角色? 如果在类型前面加上星号,则变量将通过引用传递(记住指针,它也在那里),因此,在方法内部,我们将使用特定类型,而不是其副本。



从上图可以看出, UpdateName没有意义,因为它更改了结构的副本,而不是原始副本。 并且此副本不返回。 虽然SetName将更改原始结构(由于星号和引用传递)。

结构中的方法是继承的 (并根据属性继承的规则),即 父结构可以访问嵌套在其结构中的所有方法。

其他类型可以具有方法,而不仅仅是结构。 这似乎是来自子网的扩展方法,但没有。 Go中的方法只能针对本地类型创建,即 在此程序包中声明的类型(有关程序包的进一步说明)。

包,范围,命名空间


刚才我意识到Go没有NEIMSPACE! 一般! 当编译后出现错误时,我意识到这一点,他们说在一个文件夹中我有两个使用main方法的文件。 事实证明,在编译阶段,爸爸的所有东西似乎都粘在一块画布上! 文件夹实际上是名称空间。 同志们,真是太神奇了:)

顺便说一句,这就是码头所说的:



自己注意: 抽烟码头
这是该主题中的另一篇小文章: https : //www.callicoder.com/golang-packages/#the-main-package-and-main-function

因此,他们说,基本文件夹结构如下所示:


bin-编译的二进制文件
pkg-临时目标文件
src-来源
程序包是指程序包文件所在的文件夹的名称。 是的,一个包中可以包含许多相互导入的文件。

另一个有趣的规则:以大写字母开头的函数,属性,变量和常量可以在包外部使用 ,即 被进口 。 带有小写字母的所有内容仅在包装内使用。 子网访问修饰符的类似物。

import关键字在文件而不是包中起作用。

介面


这里的接口很有趣。 我们不需要从结构继承接口。 作为采用接口类型的某种方法的输入参数而来的结构,实现该接口的方法就足够了。 而且没有问题。 即 接口方法不一定必须由该结构实现。 但是结构应包含特定功能所需的所有方法的实现,其中接口类型用作输入参数。

事实证明,与Go相比,该接口是使用它的功能的特征,而不是特定结构(对象)的特征。

如果更简单,那么逻辑是这样的:您不必为了成为鸭子而发出嘎嘎声。 如果您知道如何嘎嘎叫,那么您很可能是鸭子:)
顺便说一句,如果您的结构实现某个接口的所有方法,则可以将此结构分配为已实现接口的变量的值 。 像这样的东西:)

类型开关盒


Go有一个特殊的开关盒,可以根据传入的类型工作。 很酷的事情:



顺便说一下,这是将一种类型转换为另一种类型的方法 (例如,将接口类型转换为结构类型,以获取无法从该接口访问的结构字段):



ok-转换成功的布尔符号。 我们已经遇到了迹象:)

空接口是Go世界中的野兽。 它可以是任何类型。 诸如动态对象嵌入之类的东西。 例如,它在fmt.Println()和实现中使用空接口的类似函数中使用。

接口可以相互构建,从而构成接口(在SOLID原理的字母I (接口隔离)中说)

测验


在Go中,所有测试功能均以单词Test开头,并且接受测试模块testing的输入。 文件由测试文件的名称+单词_test命名( main_test.go-测试main.go文件)。 而且,测试和测试文件都在一个包中!



结语


仅此而已! 感谢您的关注,我准备在评论中讨论问题。 我将在课堂上的以下笔记中与您会面!

PS:您可以查看本周在github上进行培训的所有代码介绍

Source: https://habr.com/ru/post/zh-CN455830/


All Articles