TON(四)底层编译——PROGRAM{

系列文章目录

文章目录

  • 系列文章目录
  • 前言
  • 一、PROCGRAM{ 是什么?
  • 二、详细分析PROCGRAM{
    • 1. 0 =: main
    • 2. @proclist null!
      • variable ( – )
      • hole ( – p)
      • box (x – p)
      • 示例
    • 3. @proccnt 0!
    • 4. @gvarcnt 0!
    • 5. { bl word @newproc } : NEWPROC
      • @declproc


前言

这次我们将详细讲解PROGRAM{,在上一期我们介绍了 PROC 这次将介绍一下对于fift程序的识别接口。PROCGRAM{

一、PROCGRAM{ 是什么?

在fift源代码编译中,PROGRAM{ 是fift函数的开头文件,他的源代码位于 asm.fif

{ 0 =: main  @proclist null!  @proccnt 0!  @gvarcnt 0!{ bl word @newproc } : NEWPROC{ bl word dup (def?) ' drop ' @newproc cond } : DECLPROC{ bl word dup find{ nip execute <> abort"method redefined with different id" }{ swap 17 @declproc }cond } : DECLMETHOD{ bl word @newglobvar } : DECLGLOBVAR"main" 0 @proclistadddictnew dup @procdict !@procinfo !  16 0 @procinfo!
} : PROGRAM{

接下来笔者花了一上午的时间整理了所有相关的定义:

{ 0 =: main  @proclist null!  @proccnt 0!  @gvarcnt 0!{ bl word @newproc } : NEWPROC{ bl word dup (def?) ' drop ' @newproc cond } : DECLPROC{ bl word dup find{ nip execute <> abort"method redefined with different id" }{ swap 17 @declproc }cond } : DECLMETHOD{ bl word @newglobvar } : DECLGLOBVAR"main" 0 @proclistadddictnew dup @procdict !@procinfo !  16 0 @procinfo!
} : PROGRAM{
variable @proccnt
variable @proclist
variable @procinfo
variable @gvarcnt
variable @procdict
19 constant @procdictkeylen{ @proccnt @ 1+ dup @proccnt ! 1 @declproc } : @newproc{ over @procdictkeylen fits not abort"procedure index out of range"over swap dup @procinfo~!  2dup @proclistadd1 'nop does swap 0 (create)
} : @declproc• fits (x y – ?), checks whether Integer x is a signed y-bit integer (i.e.,
whether −2y−1 ≤ x < 2y−1 for 0 ≤ y ≤ 1023), and returns −1 or 0
accordingly{ not 2 pick @ and xor swap ! } : ~!{ pair @proclist @ cons @proclist ! } : @proclistadd{ bl word dup (def?) ' drop ' @newproc cond } : DECLPROCcons (h t – l), constructs a list from its head (first element) h and
its tail (the list consisting of all remaining elements) t. Equivalent to
pair.(create) (e S x – ), creates a new word with the name equal to String S
and definition equal to WordDef e, using flags passed in Integer 0 ≤
x ≤ 3, cf. 4.5. If bit +1 is set in x, creates an active word; if bit +2 is
set in x, creates a prefix word.• (compile) (l x1 . . . xn n e – l′), extends WordList l so that it would
push 0 ≤ n ≤ 255 values x1, . . . , xn into the stack and execute the
execution token e when invoked, where 0 ≤ n ≤ 255 is an Integer. If e
is equal to the special value ’nop, the last step is omitted.• does (x1 . . . xn n e – e′), creates a new execution token e′ that would
push n values x1, . . . , xn into the stack and then execute e. It is roughly
equivalent to a combination of ({), (compile), and (}).{ find 0<> dup ' nip if } : (def?)nip (x y – y), removes the second stack entry from the top, cf. 2.5.
Equivalent to swap dropfind (S – e −1 or e 1 or 0), looks up String S in the dictionary
and returns its definition as a WordDef e if found, followed by −1 for
ordinary words or 1 for active words. Otherwise pushes 0.{ @gvarcnt @ 1+ dup @gvarcnt ! @declglobvar } : @newglobvar{ 1 'nop does swap 0 (create) } : @declglobvar• dictnew ( – D), pushes a Null value that represents a new empty
dictionary.

二、详细分析PROCGRAM{

让我们逐步分析这段代码的执行过程,并解释每一行代码的含义:

1. 0 =: main

这行代码定义了一个标签main并将其值设置为0。在某些编程语言中,这可能是用来标记程序入口点的,但在这段代码的上下文中,它可能仅仅是为main这个词(word)赋了一个初始值。

注意在这个之后,我们可以find到具体的main,因为在fif中,变量是全局的,字典是全局的,如下面所示如果是0 =: main则输出为空,若没有0 =: main 则输出为main 1

variable @proccnt
@proccnt 0!
0 =: main
{ @proccnt @ 1+ dup @proccnt !  } : Dp
{  bl word dup find 0<> dup  ' nip if ' drop ' Dp  cond } : DD
DD main .s 

具体原因就是 cond有没有执行 drop ,if 有没有 nip。

当然上面的程序还可以改写为

variable @proccnt
@proccnt 0!
0 =: main
{ @proccnt @ 1+ dup @proccnt !  } : Dp
{  bl word dup find 0<>  ' 2drop ' Dp  cond } : DD
DD main .s 

使用’ 2drop来代替 dup ’ nip if ’ drop 节省了一个条件推断的操作节省了一些储存的gas,这对于func又是进一步的优化。这也体现了,func 并没有完全优化gas。

2. @proclist null!

首先复习一下盒子box
在堆栈式编程语言中,variable, hole, 和 box 是用来创建和管理数据存储位置的操作符。让我们详细分析这些操作符:

variable ( – )

  • 用途:定义一个新的变量。
  • 操作:读取输入中的空白分隔的单词名 S,分配一个空的盒子(box),并定义一个新的普通单词 S 作为一个常量。当调用这个单词时,它会将这个新盒子的地址推入堆栈。
  • 等效操作:等同于 hole constant
    • hole 创建一个新的盒子 p,这个盒子不包含任何值。
    • constant 定义一个新的单词,使其成为一个常量,当调用时,它会将一个常数值推入堆栈。
    • 因此,hole constant 首先创建一个空盒子,然后将这个盒子的地址定义为一个常量。

hole ( – p)

  • 用途:创建一个新的盒子。
  • 操作:创建一个新的盒子 p,这个盒子不包含任何值。
  • 等效操作:等同于 null box
    • null 是一个表示空值的特殊值。
    • box 创建一个新的盒子,包含指定的值。
    • 因此,null box 首先创建一个空盒子,然后将 null 值存储在这个盒子里。

box (x – p)

  • 用途:创建一个包含指定值的盒子。
  • 操作:创建一个新的盒子 p,并将指定的值 x 存储在这个盒子里。
  • 等效操作:等同于 hole tuck !
    • hole 创建一个新的盒子。
    • tuck 将堆栈顶部的值复制并插入到堆栈的第二位置(即下面一个位置)。
    • ! 是赋值操作,将堆栈顶部的值存储到堆栈第二位置的地址指向的位置。
    • 因此,hole tuck ! 首先创建一个空盒子,然后将堆栈顶部的值复制并插入到堆栈的第二位置,最后将这个值存储到新创建的盒子里。

示例

假设我们要定义一个变量 counter 并初始化为 0

  1. 使用 variable

    variable counter
    

    这会创建一个名为 counter 的新变量,它指向一个空盒子。

  2. 使用 holeconstant

    hole constant counter
    

    这会创建一个空盒子,并将这个盒子的地址定义为 counter

  3. 使用 box

    0 box counter !
    

    这会创建一个包含值 0 的盒子,然后将这个盒子的地址赋值给 counter

  4. 使用 hole, tuck, 和 !

    hole tuck 0 !
    constant counter
    

    这会创建一个空盒子,将 0 复制并插入到堆栈的第二位置,然后将 0 存储到新创建的盒子里,最后将这个盒子的地址定义为 counter。操作符提供了灵活的方式来创建和管理变量和盒子,使得数据存储和访问更加高效和直观。

回到代码中,将@proclist变量设置为null,即空值。这意味着初始化了一个空的过程列表。
在这段代码中,null!是一个操作符,它的作用是将null值存储到一个盒子(box)中。在Forth语言和一些类似的堆栈式编程语言中,盒子(box)是一种数据结构,用来存储单一的值。这个值可以是任何类型的数据,比如数字、字符串、甚至其他盒子。

让我们分解null!操作符的组成部分:

  • null:这是一个特殊的值,通常用来表示“没有值”或者“空值”。在很多编程语言中,null是一个预定义的关键字,用来表示空指针或者未初始化的变量。

  • !:这个符号通常表示赋值操作。在堆栈式编程语言中,赋值操作通常涉及到从堆栈中弹出值并将其存储在指定的位置。! (x p – ), stores new value x into Box p.

  • (p – ):这是操作符的堆栈效应(stack effect),它描述了操作符如何影响堆栈。在这个例子中,(p – )意味着操作符接受一个盒子(表示为p)作为输入,并在执行后不返回任何值(表示为)。换句话说,这个操作符会消耗堆栈顶部的一个盒子,并在其中存储null值。

现在,让我们看看null!操作符的等效操作null swap !

  • null:这是我们要存储的值。
  • swap:这是一个堆栈操作,它会交换堆栈顶部的两个值。在这个上下文中,如果我们先swap,那么盒子(p)就会移动到堆栈的顶部,而null值就会在下面。
  • !:这是一个赋值操作,它会将堆栈顶部的值(在swap操作之后,这就是盒子p)赋值为堆栈中下一个顶部的值(在swap操作之后,这就是null)。

所以,null!操作符的执行步骤如下:

  1. null值压入堆栈。
  2. 将盒子p压入堆栈。
  3. 执行swap操作,这样盒子p就在堆栈的顶部,而null值就在下面。
  4. 执行!操作,将盒子p存储的值更新为null

这个操作符的目的是将一个盒子的内容设置为null,这在初始化数据结构或者清除不再需要的值时非常有用。在堆栈式编程语言中,这种操作符的设计使得值的存储和检索非常直观和高效,因为它们直接与堆栈操作相对应。

3. @proccnt 0!

这行代码将@proccnt变量设置为0,即过程计数器初始化为0
遇上面的类似,这里继续复习一下 ,如果使用 swap 来实现 @proccnt 0! 的操作,需要确保变量和值的顺序正确,以便执行赋值操作。

  1. 0:这是我们要赋值的值。
  2. @proccnt:这是我们要赋值的目标变量。
  3. swap:这个操作会交换堆栈顶部的两个元素。

在没有 swap 的情况下,赋值操作通常是这样的:

0 @proccnt !

这将 0 压入堆栈,然后 @proccnt 操作将 proccnt 的地址压入堆栈,最后 ! 操作弹出这两个值并将 0 赋值给 proccnt

使用 swap,我们需要先压入变量,然后压入值,再使用 swap 来交换它们的位置,最后使用 ! 来完成赋值。代码如下:

@proccnt 0 swap !

执行步骤如下:

a. @proccnt 被压入堆栈,此时堆栈顶部是 proccnt 的地址。

b. 0 被压入堆栈,现在堆栈顶部是 0,下面是一个 proccnt 的地址。

c. swap 被执行,它交换了堆栈顶部的 0proccnt 的地址,现在 proccnt 的地址在顶部,0 在下面。

d. ! 被执行,它弹出堆栈顶部的 proccnt 的地址和下面的 0,然后将 0 赋值给由 proccnt 的地址指向的内存位置。

4. @gvarcnt 0!

这行代码将@gvarcnt变量设置为0,即全局变量计数器初始化为0

5. { bl word @newproc } : NEWPROC

这行代码定义了一个新的词(word)NEWPROC,它是一个函数,当调用时会创建一个新的过程(procedure)。bl word是一个函数或操作,用于接受外面的新的词(word)bl 是32 空格的代码,意味着词语将会从空格分割,而如果是0 word 则不会分割。
@newproc是实际创建过程的函数。这里定义了一个名为 @newproc 的新词。让我们逐步分析这个词的定义:

{ @proccnt @ 1+ dup @proccnt ! 1 @declproc } : @newproc
  1. @proccnt @

    • @ 是一个用于变量访问的操作符,它将变量的值推入堆栈。
    • @proccnt 是一个变量,它存储当前定义的过程的数量。
    • 执行 @proccnt @ 会将 @proccnt 变量的当前值推入堆栈。
  2. 1+

    • 这是一个简单的加法操作,它将堆栈顶部的值加一。
    • 由于 @proccnt @ 已经将 @proccnt 的值推入堆栈,1+ 将这个值加一,得到新的过程计数。
  3. dup

    • dup 是复制操作,它会复制堆栈顶部的值并再次推入堆栈。
    • 执行 dup 后,堆栈顶部将有两个相同的值,都是 @proccnt 的新值。
  4. @proccnt !

    • ! 是赋值操作,它将堆栈顶部的值弹出并存储到堆栈第二位置的变量中。
    • @proccnt ! 将堆栈顶部的值(@proccnt 的新值)赋值回 @proccnt 变量,更新过程计数。
  5. 1 @declproc

    • 这里 1 是传递给 @declproc 的参数,可能表示某种标志或特定的值。
    • @declproc 是一个词(word),它用于声明一个新的过程。
    • 1 @declproc 调用 @declproc 并传递 1 作为参数,这可能指示 @declproc 执行特定的操作,如创建一个新的过程或更新过程列表。
  6. : @newproc

    • : 是定义新词的操作符,它将跟随的代码块定义为一个新的词,并将其与词名 @newproc 关联。
    • 执行 @newproc 将执行上述步骤,即增加过程计数,更新 @proccnt 变量,并调用 @declproc 来声明新的过程。
      @newproc 这个词的作用是创建一个新的过程。它首先获取当前的过程计数,将其加一,然后将新值存储回 @proccnt 变量。最后,它调用 @declproc 来实际声明新的过程,可能还传递了一些额外的参数或标志。这个过程确保了每次调用 @newproc 时,都会正确地更新过程计数并声明新的过程。

@declproc

先看前半部分,熟悉 abort"message" 的概念和代码段 over @procdictkeylen fits not abort"procedure index out of range",分析错误检查和处理的过程。这也是fift很通用的过程,笔者称之为取反求解。因为abort只有在true时候才被触发。

  1. over

    • 这个操作符复制堆栈顶部的值,使得这个值可以在接下来的操作中使用两次。
  2. @procdictkeylen

    • 这个变量存储了过程字典键的最大允许长度19。
  3. fits

    • 这个操作符检查堆栈顶部的值(复制的过程索引)是否适合在 @procdictkeylen 位内表示的有符号整数范围内。如果适合,返回 0 (false);如果不适合,返回 -1 (true)。
  4. not

    • 如果 fits 返回 -1 (true),表示过程索引不适合指定的范围,not 操作将其取反得到 0 (false)。
    • 如果 fits 返回 0 (false),表示过程索引适合指定的范围,not 操作将其取反得到 -1 (true)。
  5. abort"procedure index out of range"

    • 如果 not 操作的结果是 -1 (true),即过程索引不适合指定的范围,那么执行 abort"procedure index out of range"
    • 这个操作抛出一个异常,异常信息为 “procedure index out of range”。

异常处理

  1. 抛出异常

    • abort"procedure index out of range" 被执行时,它会抛出一个 fift::IntError 异常,异常的值等于指定的错误消息字符串 “procedure index out of range”。
  2. 异常表示

    • 在 C++ 中,这个异常由 fift::IntError 类表示,其构造时传入的错误消息就是 “procedure index out of range”。
  3. 异常处理

    • 这个异常通常由 Fift 解释器内部处理。
    • 解释器会中止所有执行,直到到达顶层环境,并打印出错误消息。
  4. 错误信息

    • 错误消息包括:
      • 源文件名:解释器正在执行的源代码文件的名称。
      • 行号:发生错误的代码行号。
      • 当前解释的词:发生错误时解释器正在解释的词(word)的名称。
      • 指定的错误消息:“procedure index out of range”。
        剩下的部分关于@procinfo~!我们会单独做一期。在 Fift 语言中, pair @proclist @ cons @proclist ! 这行代码涉及到几个操作,包括 pair 、 @proclist 、 cons 和 ! 。让我们详细解释每个部分:
  5. @proclist :
    这是一个变量,它存储了当前的过程列表。在 Fift 中, @ 符号通常用于访问变量的值。

  6. @proclist @ :
    这部分代码读取 @proclist 变量的值并将其推入堆栈。这样,堆栈顶部就有了过程列表的值。

  7. pair :
    pair 是一个操作符,它创建了一个新的单元(cell),其中包含两个值。在 Fift 中,单元(cell)是一种数据结构,可以存储多个值。

  8. cons :
    cons 是一个操作符,它用于构造一个新的列表元素,通常包含一个头部(head)和一个尾部(tail)。在这里,它可能与 pair 操作符结合使用,以创建一个新的单元,其中包含过程的名称和过程列表。

  9. cons @proclist ! :
    cons 将新的过程(作为头部)与现有的过程列表(作为尾部)结合起来,形成一个新的列表。
    @proclist ! 将这个新构造的列表赋值回 @proclist 变量,更新过程列表。

  10. { bl word dup find { nip execute <> abort"method redefined with different id" } { swap 17 @declproc } cond } : DECLMETHOD

    这行代码定义了一个新的词(word)DECLMETHOD。它是一个函数,用于声明一个新的方法。它首先复制传入的词,然后在字典中查找这个词。如果找到了,并且执行nip execute <>的结果不是预期的(即方法已经被定义但ID不同),它会抛出一个错误。如果没有找到,它会使用@declproc函数和17这个数字来声明一个新的过程。

  11. { bl word @newglobvar } : DECLGLOBVAR

    这行代码定义了一个新的词(word)DECLGLOBVAR。它是一个函数,用于声明一个新的全局变量。它使用@newglobvar函数来创建一个新的全局变量。

  12. "main" 0 @proclistadd

    这行代码将字符串"main"和数字0作为参数传递给@proclistadd函数,这个函数将它们添加到过程列表中。这可能是将main过程添加到过程列表中。

  13. dictnew dup @procdict !

    这行代码创建了一个新的空字典,并将其复制,然后将复制的字典赋值给@procdict变量。这可能是为了初始化一个空的过程字典。

  14. @procinfo !

    这行代码将@procinfo变量设置为null或空值,可能是为了初始化过程信息。

  15. 16 0 @procinfo!

    这行代码将@procinfo变量设置为16 0,可能是为了初始化过程信息的某个特定部分。

  16. } : PROGRAM{

    这行代码结束了PROGRAM{的定义。PROGRAM{是一个复合词(word),它包含了初始化编程环境所需的所有步骤,包括设置变量、定义过程和方法的创建规则、声明全局变量等。

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

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

相关文章

Python 爬取天气预报并进行可视化分析

今天&#xff0c;我们就来学习如何使用 Python 爬取天气预报数据&#xff0c;并用数据可视化的方式将未来几天的天气信息一目了然地展示出来。 在本文中&#xff0c;我们将分三步完成这一任务&#xff1a; 使用 Python 爬取天气数据数据解析与处理用可视化展示天气趋势 让我…

【C++】第五节:内存管理

1、C/C内存分布 看下面一段代码 int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] { 1, 2, 3, 4 };char char2[] "abcd";const char* pChar3 "abcd";int* ptr1 (int*)malloc(s…

在 Oracle 中利用 `ORA_HASH` 高效处理大规模数据:并行分片的最佳实践20241008

在 Oracle 中利用 ORA_HASH 高效处理大规模数据&#xff1a;并行分片的最佳实践 在数据处理规模越来越庞大的今天&#xff0c;如何高效地处理数百万甚至数千万条记录成为数据库性能优化的重要课题。面对这种挑战&#xff0c;单线程处理数据显然会成为瓶颈。通过使用多线程并行…

与C++内存管理和STL简介的爱恨情仇

本文 1.C/C内存分布2.C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free总结 3.C内存管理方式new/delete操作内置类型new和delete操作自定义类型 4.operator new与operator delete函数&#xff08;重要点进行讲解&#xff09;5.new和delete的实现原理内置类型自定…

制造业DT数字化之生产制造业务建模

一、工厂建模为何物&#xff1f; 对制造业人员&#xff08;人&#xff09;、设备&#xff08;机&#xff09;、材料&#xff08;料&#xff09;、工艺流程&#xff08;法&#xff09;、工厂环境&#xff08;环&#xff09;数据化管理的过程就叫工厂建模。 二、制造建模有哪几大…

HTTP 和 WebSocket

目录 HTTP是什么HTTP局限性&#xff08;HTTP1.1&#xff09;请求和响应HTTP的主要特点&#xff1a;HTTP版本&#xff1a; HTTP与TCP关系数据封装传输过程1. **协议层次模型**&#xff1a;2. **封装过程**&#xff1a;1. **应用层&#xff08;HTTP&#xff09;**&#xff1a;2. …

【操作系统】引导(Boot)电脑的奇妙开机过程

&#x1f339;&#x1f60a;&#x1f339;博客主页&#xff1a;【Hello_shuoCSDN博客】 ✨操作系统详见 【操作系统专项】 ✨C语言知识详见&#xff1a;【C语言专项】 目录 什么是操作系统的引导&#xff1f; 操作系统的引导&#xff08;开机过程&#xff09; Windows操作系…

QD1-P2 HTML 编辑器:HBuilderX

本节学习&#xff1a; HTML课程内容介绍HBuilderX编辑器的使用 本节视频 www.bilibili.com/video/BV1n64y1U7oj?p2 HTML 内容 基础语法 标签整体架构DOCTYPE 常用标签 标题和水平线段落和换行列表div 和 span格式化标签图片超链接标签表格表单字符实体 编辑器 HBuilder…

设计测试用例的方法

目录 1、等价类 2、边界值 3、场景法 4、正交表法 5、设计正交表 6、判定表法 7、错误猜想法 1、等价类 在测试中选取一些数据作为等价类进行测试&#xff0c;如果测试通过&#xff0c;就代表测试通过&#xff0c;可以用少量代表性的测试数据取得较好的测试结果。 等价类…

Oracle EBS中 电子文档归档 模块的财务流程概览

Oracle E-Business Suite (EBS) 提供了电子文档归档&#xff08;Electronic Document Archiving, EDA&#xff09;功能&#xff0c;它是一个重要的组成部分&#xff0c;帮助组织有效地管理和存储大量的业务文档。虽然在提供的资料中没有直接提及电子文档归档模块的财务流程概览…

智能扭矩系统在轨道交通行业的应用_SunTorque

【大家好&#xff0c;我是唐Sun&#xff0c;唐Sun的唐&#xff0c;唐Sun的Sun。一站式数智工厂解决方案服务商】 在现代轨道交通领域&#xff0c;安全、高效和可靠性是至关重要的考量因素。智能扭矩系统作为一项先进的技术&#xff0c;正逐渐在轨道交通行业中展现出其重要的应用…

【原创】java+springboot+mysql劳动教育网系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

Vscode+Pycharm+Vue.js+WEUI+django火锅(四)WEUI和Vue整合

Vue移动端的UI库&#xff0c;其实网上推荐的排行榜上看起来都好&#xff0c;尤其是Vuetify 特别有眼缘,因为看到了三个字“易上手”。 但是因为之前系统的Django开发&#xff0c;便于企业微信中访问选用了WEUI&#xff0c;所以还是继续使用WEUI的方案。1.安装 PS C:\website\my…

使用Milvus和Llama-agents构建更强大的Agent系统

代理&#xff08;Agent&#xff09;系统能够帮助开发人员创建智能的自主系统&#xff0c;因此变得越来越流行。大语言模型&#xff08;LLM&#xff09;能够遵循各种指令&#xff0c;是管理 Agent 的理想选择&#xff0c;在许多场景中帮助我们尽可能减少人工干预、处理更多复杂任…

golang获取当天最小的时间,以DateTime的string格式返回

推荐学习文档 golang应用级os框架&#xff0c;欢迎stargolang应用级os框架使用案例&#xff0c;欢迎star案例&#xff1a;基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识&#xff0c;这里有免费的golang学习笔…

@RequestParam @PathVirable @RequestBody @ApiParam的区别

RequestParam 最常用用value指定参数名字&#xff0c;required字段指定参数是否必须&#xff0c;默认为true&#xff0c;当requiredfalse时&#xff0c;一般配合着defaultValue"xx"使用对应的url是这样的&#xff1a; https://localhost/requestParam/test?key1va…

通俗易懂的人工智能(AI)入门教程

欢迎来到人工智能&#xff08;AI&#xff09;的世界&#xff01;无论您是对AI感到好奇&#xff0c;还是希望在未来的职业中应用AI技术&#xff0c;这篇教程将为您提供一个清晰的入门指南。我们将以简单易懂的方式&#xff0c;带您了解AI的基本概念、发展历程、主要分支及其应用…

C++与Java Web开发的对比分析:优势与差异

目录 1. 引言 2. C的开发优势与特点 2.1 高性能与硬件控制 2.2 面向对象与多范式支持 2.3 跨平台能力 3. Java Web的开发优势与特点 3.1 跨平台与广泛的企业应用 3.2 丰富的生态系统与工具支持 3.3 安全性与稳定性 4. C与Java Web的差异对比 4.1 性能与效率 4.2 开发…

基于go开发的终端版即时通信系统(c-s架构)

项目架构图 类似一个聊天室一样 整体是一个客户端和服务端之间的并发多线程网络通信&#xff0c;效果可以翻到最后面看。 为了巩固基础的项目练手所以分为9个阶段进行迭代开发 版本⼀&#xff1a;构建基础Server 新建一个文件夹就叫golang-IM_system 第一阶段先将server的大…

3303. 第一个几乎相等子字符串的下标

Powered by:NEFU AB-IN Link 文章目录 3303. 第一个几乎相等子字符串的下标题意思路代码 3303. 第一个几乎相等子字符串的下标 题意 给你两个字符串 s 和 pattern 。 如果一个字符串 x 修改 至多 一个字符会变成 y &#xff0c;那么我们称它与 y 几乎相等 。 Create the v…