C PHP Go.md

C 语言

1.visual Studio lnstaller

  1. 安装

    • 去官网下载后点击exe文件,在弹出的窗口中点击继续后,选择c++桌面开发并点击安装。

  2. 注册账号

    • 登录vsl的时候需要登录账号,所以需要试用邮箱创建一个账号。

  3. 新建项目

    • 点击新建项目后,再点击控制台应用并下一步,输入项目名称、路径、解决方案名称。

    • c的后缀是c,c++的后缀是cpp。

    • 输入这段代码并运行,用来测试是否搭建成功。

      #include<stdio.h>
      int main(){
         printf("hello world!");
         return 0;
      }

2.基本知识

  1. 注释分为单行注释和多行注释,单行注释用//来,而多行注释用/**/的中间注释。

    #include<stdio.h> //头文件包含,是在其他的包中调用函数。
    int main(){ //main函数是主函数,是程序开始的地方。
       printf("hello world!"); //打印函数
       return 0; //返回,c语言写完一行后需要加;确定结尾。
    }

2.1 关键字

  1. 数据类型关键字

    1. char 字符型 占一个字节,用单引号引起来只能使用asill的一个字符,用双引号引起来的用于字符串。

    2. short短整型,占2个字节;int整型在不同位数的操作系统下占不同位数;long长整型与int相同。

    3. float单浮点型占四个字节;double双浮点型占8个字节。

    4. signed有符号,unsigned无符号数,viod空类型。

  2. 其他关键字

    1. sizeof(data);测试占用存储空间大小

    2. typedef;用于类型重命名

      typedef long int lint //可将长的类型定义为短的
      lint data = 1
    3. volatile;容易改变,是告诉处理器每次用volatile定义的变量时,重新去内存获取。

2.3 数据类型

  • 基本数据类型:char、short int、int、long int 、float、double

  1. 变量和常量

    1. 变量是随时变化的量,常量是保持不变的量,有数字、字母、下划线组成。不能使用数字开后、不能还有空格、不能与关键字重名。

     类型 变量名|常量名 = 数据
    1. 变量风格:

    • linux风格:小写+下划线

    • 驼峰风格:首字母大写+下划线

    1. c需要区分大小写

  2. 字符和格式化输出

    1. 转义字符:以反斜杠“\”开头;每个字符串结尾会自动的添加一个结尾符“\o”。

    2. 格式化

      %d(有符号),%u(无符号)    //十进制整数
      %x(十六),%o(八)  //整数
      %f(float),%l(double),%e(树形式)   //浮点型
      %s,%c,%p     //分别是字符串,单个字符,指针的值
      特殊:
      %3d:要求宽度为3位,如果不足3位,前面补空格;
      %03d:要求宽度为3位,如果不足3位,前面补0
      %-3d:要求宽度为3位,如果不足3位,后面补空格;
      %.2f:小数点后保留2位;
  3. 构造类型和数据转换

    1. 由若干个相同或不同的类型构成的集合,这种数据类型被称为构造类型。具有特性的分别是:数组、构造体、共同体、枚举。

    2. 数据转换分为自动转换和强制转换,前者遵循一定的规律,由编译系统自动完成。后者把表达式的运算结果强制转换成需要的数据类型。

    3. 自动转换

    • 自动转换的原则是占字节数少的向占字节数多的转。

      char,short
      signed int
      unsigned int
      long,float
      double
      转换顺序为从上往下转
    • 当表达式中出现了char、short、int类型中的一种或者多种时,会将全部转为int运算。

    • 当表达式中出现了带小数点的实数参加运算时,全部以double类型的参加运算。

    • 当表达式中有有符号数和无符号数时,参加运算的成员全部变成无符号数运算。

    • 在赋值语句中等号右边的类型自动转换为等号左边的类型,注意自动类型转换都是临时的转换,并不会影响自动类型转换的变量。

2.4 运算符

  1. 算数运算符:+、-、*、/、%、+=、-=、 *=、%=

  2. 关系运算符:>、<、==、>=、<=、!=

  3. 逻辑运算符:&&、||、!

  4. 原码反码补码

    1. 正数在内存以原码存储,负数在内存以补码存储。

    2. 正数时原码=反码=补码

    3. 负数时:原码反码补码最高位是一,反码需要将剩下取反,补码是取反加一。

  5. 位运算:&、|、~(取反)、^(异或)、>>、<<

    • 算数右移高位补符号位,逻辑右移高位补零。

  6. 条件运算符:a1?d1:d2 ;如果a1满足时返回d1,不满足返回d2。

  7. 逗号运算符:a1=(d1,d2);a1等于最后边的值。

  8. 自增自减运算符:i++、i--(先用后加);--i、++i(先加后用);

  9. 运算符的优先级:算数运算和关系运算高于关系运算,关系运算高于逻辑运算。

2.5 基本结构

1.条件语句

  • if_else

  • if可以做单条件、双条件和多条件。

    if (表达式){    //单条件
       代码块
    }
    if (表达式){    //双条件
       代码块
    }else{
       代码块
    }
    if (表达式){    //多条件
       代码块
    }else if{
       代码块
    }else{
       代码块
    }
  • switch

  • switch是一个多条件,以常量表达式为主的条件语句。

    switch(表达式){    //表达式只能是字符或整型
    case 常量表达式1
           代码块
       case 常量表达式n:
           代码块
       default:代码块;
    }

2.循环语句

  • while

  • while循环是以条件循环的,条件不成功可以一直循环,也可以设置永真条件。

    while(条件){ //先判断后执行
       循环体
    }
    do { //先执行后判断
       循环体
    }while(条件);
  • for

  • for循环主要以次数的循环

    for(表达式1,表达式2,表达式3){ //表达式1只有在第一次循环时执行,表达式2时条件,表达式3是每次循环都会执行。
       循环体
    }

3.跳跃结构

  • goto

  • goto用于代码之间的跳跃,不建议使用,因为会把代码搞得很乱。

    printf(1)
    goto A //只会输出1和3
    printf(2)
    A:
    printf(3)

3.数组和函数

  1. 数组是若干个相同类型的变量在内存中有序存储的集合。

3.1 数组的定义

  1. 数组定义类型:基本型、指针型“int *a[10]”、结构体型“stract stu boy[10]”

  2. 在数组定义的时候可以不给出数组元素的个数,根据初始化的个数来定义数组的大小“int a[]={1,2,3,4,5}”。

  3. 定义二维数组的时候,可以不给出行数,但必须给出列数,二维数组的大小根据初始化的行数来定。

  4. 初始化数组

    1. 定义数组的时候,顺便给数组的元素赋初值。

    2. 全部初始化:有几个元素,赋几个值。

    3. 部分初始化:有5个元素,赋4个值。

    4. 二维逐个初始化,不用大括号分开。

  5. 数组可定义一维、二维、多维“类型 数组名[10]”。需要几维就加几个。

3.2 使用及补充

  1. 引用时是:数组名[下标];下标是元素在内存中的位置。

  2. 用字符串赋值比用字符逐个赋值多占一个字节,用于存放结束标志“\o”

  3. 输入:scanf_s("%s",str,15) //15是只能输入15个字符。(数组本身可以作为地址,就不需要&符号了)

  4. 输出:printf("hello world!") //输出hello world!

  5. 补充:

    #include<stdlib.h>
    srand((unsigned)time(null)); //以当前时间为准,设置随机种子
    ch=rand(); //生成一个随机数字
    #include<conio.h>
    ch = getch(); //实时获取键盘中输入的值
    #include<time.h>
    time(null); //获取时间
    #include<corecrt.h> //定义时间类型时需要用到的头文件
    time_t a; //定义时间类型
    system("cls"); //执行dos中的命令
    //esc在ascil中等于27;

3.3 基本函数

  • 函数是c的功能单位,实现一个功能可以封装一个函数来实现。

  • 函数分为库函数、自定义函数、系统调用函数(操作系统实现的函数)。

  • 函数可以传参数,也可以不传。

    返回类型 函数名(参数){    //不传时用void
       代码块
       return;
    }
  • 定义返回什么类型就返回什么类型,默认返回整型。

  • 函数的定义不能嵌套,即不能在一个函数体内定义另一个函数。

4.4 声明

  • 声明是要编译器认识这个函数,声明用于被调函数在主调函数下方是时或在另一个文件中时需要声明;声明分为直接声明和间接声明。

  • 直接声明是将函数的定义行复制到main的入口上方。

    void fun(void);
    int main(){
      ...
    }
    void fun(void){
      ...
    }
  • 头文件调用时用<>括起来的直接在c库中寻找,用“”引起来的先去当前目录寻找,找不到后再去c库中寻找。

    a.c
    include"as.h"
    int main(){
       fun(); //两个函数在同一目录下时,可直接调用
    }
    ----------------
    b.c
    void fun(void){
       return;
    }
    ----------------
    as.h
    extern void fun(void); //间接声明时需要用extern
    ----------------
    变量=函数名(参数); //函数的调用

4.变量的存储类别

4.1 内存的分区

  1. 内存分为物理内存和虚拟内存,操作系统会在物理内存和虚拟内存之间做映射。在32位操作系统下,每个进程的寻址范围4g;0x00000000~0xf....。

  2. 在运行程序的时候,系统会将虚拟内存进行分区。

    1. 堆:在动态申请内存的时候,在堆里开辟内存。

    2. 栈:主要存放局部变量。

    3. 静态全局区

      1. 未初始化的静态全局区:存放没有初始化的变量。

      2. 初始化的静态全局区:存放赋过初值的变量。

    4. 代码区:存放程序代码

    5. 文字常量区:存放常量。

  3. 内存以字节为单位来存储数据的,可以看成一个更大的一维字符数组。

4.2 全局变量

  • 全局变量是在main之前定义的,程序运行到结束一直存在;

  1. 普通全局变量是在其他文件中需要extern定义;所有点c都可以使用。

  2. 动态全局变量是只能在定义点c中使用。

  3. 静态全局变量是 需要在变量定义的时候前面加上static修饰;只允许定义它的点c的文件中使用。“static int num=100;”

4.3 局部变量

  • 局部变量是在函数内部或复合语句中定义的,在定义它的函数或复合语句中使用,在函数调用之前局部变量不占用空间,只有在调用的时候才会在内存中开辟空间。

  1. 普通局部变量函数结束之后就会释放。

  2. 静态局部变量也可以在函数执行之后外部使用;用static修饰,函数结束之后不会释放,以后再调用函数的时候,就不在为其开辟空间了。

  3. 复合语句用大括号括起来使用的。

4.4 内部函数和外部函数

  1. 外部函数就是普通函数,它可以被任何一个文件所调用。

  2. 内部函数在函数定义前用static修饰,内部函数只能在定义的文件中使用。

5.预处理、动态库、静态库

  • c语言编译过程分为:预处理,会将点c中的头文件和宏展开后生成点i文件、编译,将与处理之后的点i文件生成点s汇编文件、汇编,将点s汇编文件生成点o目标文件、链接,将点o文件链接成目标文件。

  • linux下的GCC编译器编译过程

    1. 预处理:gcc -E a.c -o a.i

    2. 编译:gcc -S a.i -o a.s

    3. 汇编:gcc -c a.s -o a.o

    4. 链接:gcc a.o -o a

5.1 预处理

1.include

  1. #include<>,是在系统指定下的路径下找头文件。

  2. #include“”,是先在当前目录找头文件,找不到后再去系统指定的路径寻找。

  3. include可以包含点c文件,但是不要包含点c。因为include会在预处理时展开,如果一个点c被包含多次,就会导致函数重复定义。

  4. 预处理只是对include进行处理,并不会检查语法。只有在编译阶段才会进行语法检查。

2.define

  1. 定义宏需要用到define去定义,只要修改宏定义,其他地方在预编译的时候就会重新替换,宏定义后边不用加分号,宏的作用范围是定义的地方到文件尾,如果向在中间终止需要使用“undef”。

  2. 不带参数的宏

    //预编译前
    #define pi 3.14
    int main(){
       double f;
       printf("%lf\n",pi);
       f=pi
       #undef pi
    }
    //预编译后
    int main(){
       double f;
       printf("%lf\n",3.14);
       f=3.14
       #undef pi
    }
  3. 带参数的宏在调用时需要传参,传入的参数会在预处理中保留。

  4. 带参数的宏

    //预编译前
    #define s(a,b) a*b
    int main(){
    printf("%lf\n",s(2,4));
    #undef s
    }
    //预编译后
    int main(){
    printf("%lf\n",2*4);
    #undef pi
    }
  5. 带参数宏和带参数函数的区别

    1. 带参数宏调用多次展开多次,执行代码时不需要调用,也就不需要压栈弹栈。但是浪费空间,节约时间。

    2. 带参数函数,代码只有一份,存在代码段,调用的时候去代码段取指令,调用的时候要,压栈和弹栈。但是节约空间,浪费时间。

    3. 带参函数的形参是有类型的,带参宏的形参是没有类型的

3.选择性编译

  1. 选择性编译是通过一个宏来判定的,如果宏存在就执行a代码,如果不存在就执行b代码。

    //编译前
    #define aa
    main(){
    #ifdef aa
    printf("a");
    #else
    printf("b");
    #endif
    return 0;
    }
    //编译后
    main(){
    printf("a");
    return 0;
    }
  2. 选择性编译是通过一个宏来判定的,如果宏存在就执行b代码,如果不存在就执行a代码。主要用于防止头文件重复包含。

    //编译前
    #define aa
    main(){
    #ifndef aa
    printf("a");
    #else
    printf("b");
    #endif
    return 0;
    }
    //编译后
    main(){
    printf("b");
    return 0;
    }
    //__________________----
    a.c
    main(){
    func(2,3);
    }
    int func(int a,int b){
    return a*b;
    }
    b.h //这样写即可去重重复调用头文件。
    #ifndef __FUN_H__ //宏不存在时执行
    #define __FUN_H__ //定义宏执行过一遍后,下次执行将不再走这里。
    extern int func(int a,int b);
    #endif
  3. 选择性编译是通过一个表达式来判定的,如果表达式为真就执行a代码,如果表达式为假就执行b代码。

    //编译前
    int main(){
    #if 1
    printf("a");
    #else
    printf("b");
    #endif
    return 0;
    }
    //编译后
    int main(){
    printf("a");
    return 0;
    }

5.2 静态库和动态库

  1. 动态编译是于编译的可执行文件用链接关系,失去链接后将无法使用可执行文件。

    • gcc a.c -o a

  2. 静态编译是于编译的可执行文件打包在一起,并不使链接,可以在任何地方使用。

    • gcc -static a.c -o a

  3. 静态库制作:

    1. gcc -c mylib.c -o mylib.o

    2. ar rc libtestlib.a mylib.o

    3. 注意:静态库起名的时候必须以lib开头以.a结尾。

  4. 静态库编译的二种方式:

    1. gcc -static a.c libaa.a -o a

    2. gcc -static a.c -o a -L/a/a -l asdf -I/a/a

      • -L是指库文件路径;-l是指找那个库;-I是指头文件路劲。

  5. 动态库制作:

    1. gcc -shared a.c -o libtestlib.so

  6. 动态库编译的二种方式:

    1. gcc a.c libaa.so -o a

      • 编译之前需要加环境变量,不然找不到。

      • export LD_LIBRARY_PATH=./:SLD_LIBRARY_PATH

    2. gcc a.c -o a -L/a/a -l asdf -I/a/a

      • export LD_LIBRARY_PATH=./:SLD_LIBRARY_PATH

      • -L是指库文件路径;-l是指找那个库;-I是指头文件路劲。

6.指针

  1. 系统给虚拟内存的每个存储单元分配了一个编号,编号称之为地址或指针。

  2. 指针变量就是用来存储地址的,在不同位数的操作系统下指针变量的位数也不同。使用什么类型的地址,就只能存储什么类型的地址。

  3. 字符变量如果占一个字节就会有一个地址编号,如果整型占了四个字节就使用了四个存储单元也就有四个地址编号。一般用最小的地址编号来代表。

Golang

  1. 编译器是全文翻译,解释器是实时翻译。

  2. 从语言层面支持并发,非常简单,go语言就是天然并发。

初级

1.基本了解

1.环境搭建

1.1 MAC&Linux
  1. 下载编译器:

    • MAC:在golang.google.cn中点击Download Go,选择Apple macOS即可,默认安装路径是:/usr/local/go/。

    • Linux:

  2. 个人配置

    1. 创建一个任意目录用于存放你写的代码,在目录下创建三个文件夹“bin”、“pkg”、“src”。

    2. bin存放编译后的可执行文件、pkg存放包文件、src存放你的项目。

  3. 配置环境变量

    vim-/.bash_profile //进入后将环境变量写入即可
    //环境变量
    1. go编译器路径:export PATH=/usr/local/go/bin;$PATH
    2. go安装路径:export GOROOT=/usr/local/go
    3. 自己创建的路径:export GOPATH=/users/golangProjects
    4. 自己创建路径下的bin目录:export GOBIN=/users/golangProjects/bin
    1. 查看版本

      • go,进入go

      • go version,显示go的版本

  4. 测试

    cd $GOPATH //快速进入主文件夹
    cd src/
    ls //查看当前文件夹
    mkdir crm //创建project
    touch app.go //创建.go文件
    pwd //查看当前路线
    vim app.go //打开app.go文件
    """
    package main
    import "fmt"
    func main(){ //创建函数
    fmt.Println("holle world!") //调用fmt的println函数
    }
    """
    go run app.go //运行程序
    编译分为三种:
    1.{
    go build //编译
    ./crm //执行程序文件
    go build -o xx //可编译时修改文件名
    //本质是先执行go build 后保存在一个零时文件夹中,然后执行。
    }
    2.go install、go run //2&3一样都是先执行go build后,再把文件保存在相应文件中。
1.2 Windows
  1. 下载go编译器去官网下,安装编译器后选好目录并创建(注意那三个文件夹也需要创建)。

  2. 设置环境变量:

    PATH=c:/GO/bin;
    GOROOT=c:/GO
    GOPATH=e:/project/go
    GOBIN=e:/project/go/bin
  3. 开发工具:Goland,IDE(集成开发环境)

2.基础学习

2.1 初识包管理
  1. 一个文件夹可以称为一个包,在文件夹中可以创建多个文件。在同一个包下的每个为文件中必须指定相同包名称。

  2. 包分为程序包和模块包:

    1. 程序包的packagemain,程序是需要主程序运行的,所以main就需要一个主函数,这个函数只能有一个。

      package main //主包名
      func main(){ //程序主函数入口
      }
      • 程序包中可以创建子包,子包的name与子包的package name相同。同目录下创建的文件可认为是子文件夹的仓库。

      • 主程序调用同级目录下的文件函数时,可直接写函数名加括号,无需写文件名或路径。

      • 主程序调用子级目录下的文件函数时,需要在import中写入程序名/子包名才可调用函数,package名加函数名加括号。

        package main
        import(
        "luggy/api"
        )
      • 函数名首字母大写称为公共函数,其他文件可以调用。函数首字母小写称为私有函数,只能在自文件中使用。

    2. 模块包中的package是除main之外,都可以使用并且无需写main函数指定程序入口。

  3. 导入包时如果包名太长可以使用别名来调用,使用空格区分开如:

    import(
    a "luggy/api"
    )
  4. 在执行main函数之前会自动执行一个“init”的函数,这个函数不需要调用。

    // go中调用一个包后如果不用它是不会初始化编译的,但是又一种情况需要执行包中的init函数就可以在前面加一个下划线
    package main
    import(
    _ "luggy/api"
    )
    package api
    func init(){
    var a int = 1
    }

     

2.2 输出和输入
  1. 输入分为自带和模块,自带有两钟print和println。

  2. 模块也是go自带的模块“fmt”,其中有三种输出:print、println、printf。

    package main
    import"fmt"
    func main(){
    Print("baba") //print不带换行
    Println("baba") //println带换行
    fmt.Print("baba") //print不带换行
    fmt.Println("baba") //println带换行
    //printf是格式化输出,其中占位符有%s字符、%d数字、%f是小数、%.2f是保留两位小数并四舍五入。
    fmt.Printf("I'm your %s","dad")
    }
  3. 输入是计算机与人交互,输入由三种:Scan、Scanln、Scanf,这三种都返回两个值,count,err。

    • Scan是要求输入两个或多个时,必须输入相对应的数据,不然会一直等待,每个值用空格分割。

    • Scanln是不管输入几个,只要回车就结束输入状态。

    • Scanf是格式化输入,按照指定的字符串输入并提取数据,在要提取的数据后面加上空格才可以。

      package main
      import"fmt"
      func main(){
      var name,age string
      fmt.Println("aaa")
      //count,err := fmt.Scan(&name,&age)
      //count,err := fmt.Scanln(&name,&age)
      count,err := fmt.Scanf("我是你%s,今年%s"&name,&age)
      fmt.Println(name,count,age)
      }
    • 这三种输入都有一个问题,不能还有空格。因此有一种方式解决。

      package main
      import (
      "bufio"
      "os"
      "fmt"
      )
      func main(){
      /*
      os.Stdin是正则输入,可以将输入的存储起来。
      bufio.NewReader()是将输入的转为reader对象。
      reader.ReadLine()是读取并返回三个参数。
      isprefix=false是一次性读完
      isprefix=True是未读完
      */
      reader:= bufio.NewReader(os.Stdin)
      Line,isprefix,err := reader.ReadLine()
      data:=string(Line)
      fmt.Println(isprefix,data,err)
      }
  4. 注释:单行注释用//,而多行注释用/**/

  5. 字符串格式化

    package main
    import "fmt"
    func main(){
    var a,b string
    fmt.Scan(&a,&b)
    fmt.Printf("我是你%s,永远都是你的%s",a,b)
    }
2.3 初识数据类型
  1. 整型(int)

    • 整型是由10个基数组成的,可以进行运算。

  2. 字符串(string)

    • 双引号引起来的字符、数字、符号都称为字符串,字符串之间可以相加。

  3. 布尔型(bool)

    • 布尔型有两个状态truefalse,计算机中只有真和假。

2.4 变量和常量
  1. 变量是由字母、数字、下划线组成,不能以数字开头,不能使用关键字。

    //变量分为定义和赋值,定义时不赋初值默认是int型默认值是0、string默认值是“”、bool默认值是false
    var age int //定义未赋初值,默认是0
    var name string = "123" //定义并赋值
    age = 12 //赋值
  2. 起名时建议使用:见名知意、驼峰式。

  3. 变量简写

    var name="alex"
    name := "alex"
    var name,age,data string
    var( //这种称为因式分解
    name="alex"
    age="18"
    num int
    )
  4. 常量是保持不变的量,在局部和全局都可以使用,通过const定义并赋值。

    package main
    main(){
    const data = 999
    const(
    pi=123
    gender="boy"
    )
    }
2.5 作用域和赋值及内存
  1. 作用域程序层次化,以大括号区分、上级不能使用子级变量,上级可以使用同级变量,下级可以使用上级变量。

  2. 全局变量是在入口外,不可以使用:=定义变量。

  3. a="1234",b=a时b会复制a,而并不会指向同一个内存地址,在变量前加上&可以查看内存地址,当赋值时内存位置不变,但只会变。

  4. 注意:使用int、string、bool这三种数据类型时,如果遇到变量的赋值则会拷贝一份(赋值型)。

2.6 iota
  1. iota可以在因式分解中使用,用来给多个常量或者变量赋连续的值,iota的作用是在需要定义连续值的时候使用。

    package main
    main(){
    //会自动给后面的变量赋值,值是连续的
    const(
    v1 = iota //0
    v2 //1
    v3 //2
    )
    }
2.7 编码
  1. ascii以8位表示,最高位用于表示正负。

  2. Unicode分为ucs2(16位表示)和ucs4(32位表示)。

  3. utf-8是Unicode的压缩,以码位范围选择模板。

2.8 内置函数
  1. 不用调用就可以使用的函数

    close // 主要用来关闭channel
    len // 计算长度
    new // 用于分配内存,主要用来分配值类型,返回指针
    make // 用于分配内存,主要用来分配引用类型。
    append // 用来追加元素到数组
    panic and recover // 用来做错误处理

     

2.语句和运算符

2.1条件结构

  1. if语句可以用于单分支、双分支和多分枝。

    package main
    import "fmt"
    func main(){
    var number int
    fmt.Println("请输入数字")
    fmt.Scanln(&number)
    if number >0{
    fmt.Println("你输入的数字是个正数")
    }else if number <0{
    fmt.Println("你输入的数字是个负数")
    }else{
    fmt.Println("你输入的是0")
    }
    }
  2. switch也是多分支,使用表达式的结果,再于条件比较。

    package main
    import "fmt"
    func main(){
    var number int
    fmt.Println("请输入数字")
    fmt.Scanln(&number)
    switch true{
    case number==1:
    fmt.Print("a")
    case number==2:
    fmt.Print("b")
    default: //所有条件不满足时触发。
    fmt.Print("c")
    }
    }

2.2 循环

  1. for循环,循环是将一段代码重复执行,for循环默认是true。

    for(){ //不加条件会一直循环
    循环体
    }
    for(表达式1,表达式2,表达式3){ //表达式1只有在第一次循环时执行,表达式2时条件,表达式3是每次循环都会执行。
    循环体
    }
  2. continue是结束本次循环执行下次循环,break是结束循环。

2.3 跳跃

  1. goto语句,跳跃是指从一个地方跳到一个地方。

    package main
    import "fmt"
    func main(){
    fmt.Println("a")
    goto A //A的跳跃点
    fmt.Println("b")
    A: //A的降落点
    fmt.Println("c")
    }

2.4 运算符

  1. 算数运算符:*、/、%、+、-、++、--

  2. 关系运算符:==、!=、<、>、<==、>==

  3. 逻辑运算:&&、||、!

  4. 位运算:&(与)、|(或)、^(异或)、<<(左移)、>>(右移)、&^(以前面的位基准,让前后的值比较,如果都是1,则将前面的值是1的改为0.)

  5. 赋值运算符:=、+=、-=、/=、%=、<<=、>>=、&=、^=、|=

  6. 运算符优先级:位运算高于算数运算高于关系运算高于逻辑运算。

 

 

3.数据类型

3.1 整型

  1. go 中的整型分为有符号和无符号,有符号包含负号。

  2. 有符号整型分为int8、int16、int32、int64,计算方式是2的几次方。32位操作系统下是2的32次方,正负各占一半。

  3. 无符号整型相同64位操作系统下2的64次方个,正号全占。

  4. 整型的转换

    package main
    import (
    "fmt"
    "reflect"
    "strconv"
    )
    func main(){
    //1.整型之间的转换
    var v1 int8 =12
    var v2 int16 =23
    v3 :=int16(v1)+v2 //这样可以将其直接转换
    fmt.Println(v3)
    //2.整型与字符串之间的转换
    result:=strconv.Itoa(16) //将整型转为字符串
    fmt.Println(result,reflect.TypeOf(result)) //typeof是查看数据类型
    result1,err:=strconv.Atoi("234") //将字符串转为整型,如果是无法转换的字符err会告诉你的。
    fmt.Println(result1,reflect.TypeOf(result1),err) //typeof是查看数据类型
    }
  5. 进制之间的转换

    package main
    import(
    "strconv"
    "fmt"
    )
    func main(){
    //只有十进制是整型形式存在的,其他都是字符形式存在。
    v1:=strconv.FormatInt(int64(64),16) //十进制转其他进制
    fmt.Println(v1)
    //第一个参数是数据,第二个参数是数据的进制,第三个参数是要转成的进制
    result,err:=strconv.ParseInt("123D",16,0)
    fmt.Println(result,err)
    }
  6. 常见的数学运算

    package main
    import"math"
    func main(){
    math.Abs(v1) //取绝对值
    math.Floor(v1)//取最小整数
    math.Ceil(v1) //取最大整数
    math.Round(v1)//四舍五入
    math.Mod(v1,v2) //取余数
    math.Pow(v1,v2) //计算次方
    math.Pow10(v2) //计算10的几次方
    math.Max(v1,v2) //取最大值
    math.Min(v1,v2) //取最小值
    }
  7. 指针是用来存储内存地址的,主要用于节省内存空间;有两钟定义方式

    • var 变量 * int; //这种创建后默认值是“nil”,它们所存储的内存地址相同

    • 变量:=new(int) //这种创建后默认值是“0”,它们会创建后并指向那块内存地址。

    • nil代表的是空,new用于创建内存并进行内部数据的初始化,而且返回一个指针类型。

2 超大整型
  1. 使用超大整型需要导入“math/big”模块,用big.int来定义。

    import "math/big"
    func main(){
    var v1 := new(big.Int) //也可以创建指针形式的超大整型
    var v2 big.Int //定义超大整型
    v2.SetInt64(12) //通过int64来赋值,最大不能超过2的64次方。
    v2.SetSrting("2222",10) //通过字符串的形式来赋值的,并不受大小限制。第一个参数是数据,第二个参数是进制。
    v3:=big.NewInt(21) //newint可以完成定义并赋值。
    }
  2. 超大整型的基本加减乘除

    v1 := big.NewInt(11)
    v2 := big.NewInt(21)
    result := new(big.Int)
    //加
    result.Add(v1,v2)
    //减
    result.Sub(v1,v2)
    //乘
    result.Mul(v1,v2)
    //除
    result.Div(v1,v2)
    //除,得商和余
    miner := new(big.Int) //存余
    result.DivMod(v1,v2,mider) //存商
    var r1 big.Int
    r1.Add(&v1,&v2) //如果需要将其转换为指针类型,也可以使用变量前面加&的方式来实现。

3.2 浮点数

1.go自带
  1. 浮点数,在go中分为Float32(4个字节)和Float64(8个字节)。

    package main
    import"fmt"
    func main(){
    var v1 float32 //定义浮点型
    var v2 float32
    v1=0.1
    v2=0.2
    fmt.Println(v1+v2)
    }
  2. float底层存储原理

    1. 先将浮点型数据转换位二进制,整数/2,小数*2。

    2. 科学计数法表示,就是首位为1,剩下的均为小数,用2的n次方来实现。

    3. 存储:以float32为例存储浮点型数据,32位会分为sign、exponent、fraction

      • sign,占最高位的1位字节来表示正负、0表示正数、1表示负数。

      • exponent,除最高一位占8位,共有256种但是正负(-127~128)。存储2的几次方数

      • fraction,存储所有小数数据。

      • float64:sign=1\exponent=11\fraction=52

2.第三方库
  1. decimal需要在本地的Go环境中先安装再使用。第三方包源码地址:https://github.com/shopspring/decimal

  2. 安装第三方包

    go get github.com/shopspring/decimal

    命令执行完成,在$GOPATH/src的目录下就会出现github/shopspring/decimal的目录,这就是第三方模块安排的位置。

  3. 使用decimal包

    package main
    import(
    "fmt"
    "github.com/shopspring/decimal"
    )
    func main(){
    var v1 = decimal.NewFromFloat(0.000002)
    var v1 = decimal.NewFromFloat(0.00422)
    //加
    var v3 = v1.Add(v2)
    //减
    var v3 = v1.Sub(v2)
    //乘
    var v3 = v1.Mul(v2)
    //除
    var v3 = v1.Div(v2)
    fmt.Println(v3,v4,v5,v6)
    var price = decimal.NewFromFloat(2.345)
    var data1 = price.Round(1) //四舍五入,保留一位小数
    var data2 = price.Truncate(1)//保留一位小数
    fmt.Println(data1,data2)
    }

3.3 布尔类型

  1. 表示真假,一般是和条件等配合使用,用于满足某个条件时,执行每个操作。

    package main
    import(
    "fmt"
    "strconv"
    )
    func main(){
    //字符串转布尔值
    //true:"1","t","T","true","TRUE","True"
    //false:"0","f","F","false","FALSE","False"
    v1,err := strconv.ParseBool("t")
    fmt.Println(v1,err)
    //布尔值转字符串
    v2 := strconv.FormatBool(false)
    fmt.Println(v2)
    }

3.4 字符串

  1. 在编写程序时,使用字符串来进行文本处理的。

    var name string = "李永强"
    fmt.Println(name[0]) //这种索引得到的是一个字节
    fmt.Println(len(name)) //这样可以查看里面有几个字节
    //字符串转为一个字节集合
    byteSet := []byte(name) //转为字节集合
    fmt.Println(byteSet) //有九个字节
    //字节集合转为一个字符串
    byteList := []byte{230,173,166,230,178,155,233,189,144}
    targetString := string(byteList)
    fmt.Println(targetString)
    //rune 将字符串转为Unicode字符集码点的集合
    tempSet := []rune(name)
    fmt.Println(tempSet)
    //rune转换为字符串
    runeList := []rune{27494,27803,40784}
    targetName := string(runeList)
    fmt.Println(targetName)
    //长度处理
    runeLength := utf8.RuneCountInString(name)
    fmt.Println(runeLength) //处理后长度就变成了3
  2. 常用功能

    package main
    import (
    "fmt"
    "strings"
    "unicode/utf8"
    )
    func main(){
    var name string = "liyongqiang"
    fmt.Println(len(name)) // 获取字节长度
    fmt.Println(utf8.RuneCountInString(name)) // 获取字符长度
    fmt.Println(strings.HasPrefix(name,"li")) // 是否以什么字符串开头,输出逻辑值
    fmt.Println(strings.HasSuffix(name,"qiang"))// 是否以什么字符串结尾
    strings.Index(s string, str string) int // 判断某字符首次存在位置并返回,不存在则返回-1
    strings.LastIndex(s string, str string) int // 判断某字符最后存在位置并返回,不存在则返回-1
    fmt.Println(strings.Contains(name,"yong")) // 判断爸爸是否在里面
    fmt.Println(strings.ToUpper(name)) // 将传入的字符串转为大写
    fmt.Println(strings.ToLower(name)) // 将传入的字符串转为小写
    fmt.Println(strings.Count(name,"a")) // 判断一个字符串中出现某个字符的次数
    fmt.Println(strings.Repeat(name,4)) // 将一个字符串重复4次
    fmt.Println(strings.TrimRight(name,"qiang"))// 从右边清理匹配的开头字母
    fmt.Println(strings.TrimLeft(name,"li")) // 从左边清理匹配的开头字母
    fmt.Println(strings.Trim(name,"l")) // 从两边清理匹配的开头字母
    // 第一个参数是数据,第二个参数是要替换的,第三个是替换成的,第四个是替换几个(-1代表全部)
    fmt.Println(strings.Replace(name,"e","i",-1))
    fmt.Println(strings.Split(name,"a")) // 按指定字符分割字符串
    fmt.Println(strings.TrimSpace(name)) // 去除字符串首尾空白字符
    fmt.Println(strings.Fields(name)[0]) // 按空格分割返回切片
    }
  3. 拼接

    package main
    import(
    "bytes"
    "fmt"
    "strings"
    )
    func main(){
    //不建议
    message := "aa"+"bb"
    fmt.Print(message)
    //建议
    dataList:= []string{"aa","bb"}
    result := strings.Join(dataList,"_")
    fmt.Println(result)
    //建议(1.10之前)
    var buffer bytes.Buffer
    buffer.WriteString("aa")
    buffer.WriteString("bb")
    data := buffer.String()
    fmt.Println(data)
    //建议(1.10之后)
    var builder strings.Builder
    builder.WriteSering("aa")
    builder.WriteSering("bb")
    value := builder.String()
    fmt.Println(value)
    }
  4. string和int互转

    package main
    import (
    "fmt"
    "strconv"
    )
    func main(){
    num := "666"
    var result = strconv.Itoa(888) //转为string
    fmt.Println(result)
    //内部调用的就是ParseInt
    var data,_ = strconv.Atoi(num) //转为int
    fmt.Println(data)
    }
  5. 字符串与字节集合和rune集合

    package main
    import (
    "fmt"
    "strconv"
    "unicode/utf8"
    )
    func main(){
    var name string ="李永强"
    //字符串转字节集合
    byteSet := []byte(name)
    fmt.Println(byteSet)
    //字节集合转字符串
    byteList := []byte{230,173,166,230,178,155,233,189,144})
    targetString := string(byteList)
    fmt.Println(targetString)
    //rune 将字符串转为Unicode字符集码点的集合
    tempSet := []rune(name)
    fmt.Println(tempSet)
    //rune转换为字符串
    runeList := []rune{27494,27803,40784}
    targetName := string(runeList)
    fmt.Println(targetName)
    }
  6. string和字符

    package main
    import(
    "fmt"
    "unicode/utf8"
    )
    func main(){
    //数字转字符串
    v1 := string(65)
    fmt.Println(v1)
    //字符串转数字
    v2,size := utf8.DecodeRuneInString("A")
    fmt.Println(v2,size)
    }
1.索引切片
  • 只能操作字符串,其他类型不可以的

    package main
    import "fmt"
    func main(){
    var name string = "李永强"
    //1.索引获取字节
    v1 := name[0]
    fmt.Println(v1)
    //2.切片获取字节区间
    v2 := name[0:3]
    fmt.Println(v2)
    //3.手动循环获取所有字节
    for i:=0;i<len(anme); i++{
    fmt.Println(i,name[i])
    }
    //4.for range循环获取所有字节
    for index,item := range name{
    fmt.Println(index,item)
    }
    //5.转成rune集合
    dataList := []rune(name)
    fmt.Println(dataList[0],string(dataList[0]))
    }
2.时间日期类型
  1. 时间 类型需要导入

    package main
    import (
    "fmt"
    "time"
    )
    func main(){
    fmt.Println(time.Now()) // 获取当前时间
    fmt.Println(time.Now().Day()) // 获取当前时间的天
    fmt.Println(time.Now().Minute()) // 获取当前时间的分钟
    fmt.Println(time.Now().Month()) // 获取当前时间的月
    fmt.Println(time.Now().Year()) // 获取当前时间的年
    // 格式化,必须使用这个时间不然显示不出来
    now := time.Now()
    fmt.Println(now.Format("02/1/2006 15:04"))
    fmt.Println(now.Format("2006/1/02 15:04"))
    fmt.Println(now.Format("2006/1/02"))
    }

     

3.5 数组

  1. 数组是由定长且元素类型一致的数据集合。

    //方式一:先声明再赋值(声明时内存中已开辟空间,内存初始化的值是0)
    var number [3]int
    number[1] =34
    //方式二:声明并赋值
    var names = [2] string{"李永强","吴佩琦"}
    //方式三:声明并赋值加指定位置
    var ages = [3]int{0:23,1:34,2:12}
    //方式四:省略个数
    var name = []string{"吴佩琦","李永强"}
    //声明指针型的数组,不会开辟内存初始值数组的值是nil
    var number*[3]int
    //声明数组并初始化,返回的是指针类型数组
    number := new([2]int)
  2. 数组不仅有一维数组还有,二维和多维

    package main
    func main(){
    name :=[][2]string{"aa","bb","cc"}
    name :=[2][2]string{"aa","bb","cc"}
    }
  3. 数组的内存地址是连续的,数组的内存地址实际上就是第一个元素的内存地址,每个字符串的内部存储:len+str。

    type stringStruct struct {
    str unsafe.Pointer
    len int
    }
  4. 可变和拷贝

    1. 可变,是指数组的大小不变而值可变。

    2. 将一个变量赋予另一个变量时会复制一份的

  5. 索引切片循环

    package main
    import "fmt"
    func main(){
    //1.长度
    name := [2]string{"aa","bb"}
    fmt.Println(len(name))
    //2.切片
    name := [2]string{"aa","bb","cc"}
    v2 := name[0:1]
    fmt.Println(v2)
    //3.循环
    name := [2]string{"aa","bb","cc"}
    for i:=0;i<len(name); i++{
    fmt.Println(i,name[i])
    }
    //4.for range循环
    name := [2]string{"aa","bb","cc"}
    for index,item := range name{
    fmt.Println(index,item)
    }
    }
  6. 给数组排序和查找

    package main
    import (
    "fmt"
    "sort"
    )
    func main(){
    var a = [...]int{1,6,3,5,7,2}
    sort.Ints(a[:]) // 使用Ints时需要传入一个切片才可以,直接将数组传入是不可以的。字符串排序也一样,使用Strings就可以。
    index := sort.SearchInts(a[:],5)// 查找返回的是排序后的位置,你不管排不排序,它内部自动会排的。
    fmt.Println(index)
    }

     

3.6 切片

  1. 切片也被称为动态数组,切片是Go中重要的数据类型,每个切片对象内部都维护着:数组指针、切片长度、切片容量三个数据。

  2. 在向切片中追加的数据个数大于容量时,内部会自动扩容且每次扩容都是当前容量的2倍(当容量超过1024时每次扩容则指增加4分之一的容量)。

  3. 创建切片

    //创建切片
    var nums []int
    var data = []int{11,22,33}
    //make只用于 切片、字典、channel
    //第二个参数是初始化个数,第三个参数是声明个数
    var users = make([]int,1,3)
    //创建切片(指针型)
    var v1 =new([]int) //只声明并不初始化
    var v2*[]int //声明后,初始化指向nil
  4. 自动扩容

    package main
    import "fmt"
    func main(){
    v1 := make([]int,1,2)
    fmt.Println(len(v1),cap(v1))
    v2 := append(v1,66)
    //v1和v2地址相同但是,因取值范围的限制v1只能取到【0】的值,v2可以取到【0:1】的值。
    v3 := append(v2,77)
    //当扩容时,地址会发生变化,v2和v3的地址就不同,给v3修改时,v2中的值并不变化。
    }
1.常用功能
  1. 长度和容量

    v1 :=[]int{11,22,33}
    fmt.Println(len(v1),cap(v1))
  2. 索引和切片

    v1 :=[]int{11,22,33}
    v1[0]//注意虽然定义了,但是没有初始化或赋值的,也不可以索引
    v1[1]
    v1[2]
    v2 :=v1[0:1]
    v3 :=v1[:2]
    v4 :=v1[1:]
  3. 追加和删除

    package main
    import "fmt"
    func main(){
    v1 :=[]int{11,22,33,44,55,66}
    v2 :=append(v1,77)
    v3 :=append(v1,88,99)
    //使用另一个切片时,需要在后面加上三个点才可以使用
    v4 :=append(v1,[]int{100,200,300}...)
    //go本身并没有删除,我们可以使用修改来实现
    //它们本身还是同一个地址,使用v1输出时就会发现,最后一个值出现了两边。
    deleteNum :=2
    v5 :=append(v4[:deleteNum],v4[deleteNum+1:]...)
    }
  4. 循环

    package main
    import "fmt"
    func main(){
    v1 :=[]int{11,22,33,44,55,66}
    for i := 0;i<len(v1);i++{
    fmt.Println(i,v1[i])
    }
    for index,value := range v1{
    fmt.Println(index,value)
    }
    }

3.7 字典类型(Map)

  1. map是以“键:值”形式存储的数据类型,这种存储方式最大的有点就是查询速度快,由应为他底层是基于哈希表存储的。

  2. 取模+拉链法大概了解一下。

    1. 写好键值对后将键转为哈希值,再将哈希值 mod 4 后将结果按顺序存储(重复时并形存储)。

  3. Map的特点是键不可以重复、键必须是可哈希的(int/bool/float/string/array)、Map是无序的。

1.声明和初始化
  1. Map的键值对增加、修改使用的都是“变量[键]=值”,map不管扩不扩容,它们的内存地址永远相同。

    //声明,声明时记得把大括号带上
    UserInfo := map[string]string{}
    //声明并初始化
    UserInfo := map[string]string{"name":"李永强","age":"18"}
    //查看
    fmt.Println(UserInfo["name"])
    for key,value := range data{
    fmt.Println(key,value)
    }
    //当map中没有此键值对时是增加,有时是修改
    UserInfo["age"]=19
    UserInfo["gender"]="男"
    //删除,参数一是map,参数二是键
    delete(UserInfo,"gender")
    //使用make,make定义时可以不加大括号
    data :=make(map[string]int)
    data["a1"]=1
    data["a2"]=2
    //new,不能直接使用只能用于map转存,定义不使用new也不加大括号的用法相同。
    value := new(map[string]int)
    value = &UserInfo
    //数组做键值对
    v1 := make(map[2]int)int)
    v1[[2]int{1,2}]=2
    v1[[2]int{1,4}]=2
    ... //代表任意类型
    //map嵌套就那么个,简单的很
2.原理解析
  1. map创建后,每个键值对会有count计数并创建桶(2**B),每个桶中可存放8个(tophash哈希值、keys、values、overflow指针)。

  2. 初始化

    1. 创建一个hmap结构体对象,生成一个哈希因子hash0并赋值到hmap对象中(用于后续为key创建哈希值)。

    2. 根据hint=10,并根据算法规则来创建B,根据B去创建桶(bmap对象)并存放在buckets数组中。

      • 当B小于4时,2^B(标准桶)

      • 当B大于4时,2^B+2^(B-4)(标准桶+溢出桶)

      • 注意:每个bmap中可以存储8个键值对,当不够存储时需要使用溢出桶,并将当前bmap中的overflow字节指向溢出桶的位置。

3.8 指针

  1. 指针相当于创建了一个地址的引用,以后根据这个引用再去获取他里面的值。

  2. 取指针的指针时,需要设置好相应的*才可以。

    name := "wupeiqi"
    var a1 *string = &name
    var a2 **string = &a1
    var a3 ***string = &a2
    //一定要把*号写够,*号代表指针的引用层数,如果只写了一个*就代表直接储存name的内存地址,而写够后a3储存a2的内存地址。
  3. 计算指针

    package main
    import (
    "fmt"
    "unsafe"
    )
    func main(){
    dataList := [3]int8{11,22,33}
    //1.获取数组第一个元素的地址(指针)
    var firstDataPtr *int8 = &dataList[0]
    //2.转换成Pointer类型
    ptr := unsafe.Pointer(firstDataPtr)
    //3.转换成uintptr类型,然后进行内存地址的计算
    targetAddress :=uintptr(ptr)+1
    //4.根据新地址,重新转成Pointer类型
    newPtr := unsafe.Pointer(targetAddress)
    //5.Pointer对象转换为int8指针类型
    value :=(*int8)(newPtr)
    //6.根据指针获取值
    fmt.Println("最终结果为",*value)
    }

3.9 结构体

  1. 结构体时一个复合类型,用于表示一组数据,结构体有一系列属性组成,每个属性都有自己的里类型和值。

  2. 定义

    type 结构体名称1 struct {
    字段 类型 标签 //标签可加可不加,主要用于提示。
    }
    type 结构体名称2 struct {
    字段 类型 标签
    字段 结构体名称1 //这种是结构体嵌套
    结构体名称1 //这种也是结构体嵌套,但是结构体名称1也是结构体名称2中的字段。也称匿名字段
    }
  3. 初始化

    //可以按位置用逗号分割,给赋予不同类型的数据。
    var 结构体对象 = 结构体名称2{"数据",17}
    结构体对象.字段 //这样可以获取对应的值。
    //定义一个结构体
    type ageN struct {
    age int
    }
    type genderS struct {
    gender string
    }
    type Person struct {
    name string
    hobby []string
    agen ageN
    genderS
    }
    //方式一:先后顺序
    var p1 = Person{"liyongqiang",[]string{"computer"},ageN{12},genderS{"男"}}
    fmt.Println(p1.name,p1.hobby,p1.agen.age,p1.gender)
    //方式二:关键字
    var p2 = Person{name:"liyongqiang",hobby:[]string{"computer"},agen:ageN{age:12},genderS:genderS{gender:"男"}}
    fmt.Println(p2.name,p2.hobby,p2.agen.age,p2.gender,p2.genderS.gender)
    //方式三:先声明再赋值
    var p3 Person
    p3.name = "liyongqiang"
    p3.hobby = []string{"computer"}
    p3.agen = ageN{age:12}
    p3.genderS = genderS{gender:"男"}
    p3.gender = "男"
  4. 结构体指针

    type Person struct {
    name string
    }
    //初始化结构体指针
    p1 := &Person{"liyongqiang"}
    p2 := *Person = new(Person)
    p2.name = "liyongqiang"
  5. 标签的查询方式

    package main
    import (
    "fmt"
    "reflect"
    )
    func main(){
    type Person struct{
    name string "姓名"
    age int32 "年龄"
    }
    p1 := Person{name:"wupeiqi",age:18}
    p1Tyep := reflect.TypeOf(p1)
    //top1
    filed1 := p1Type.Field(0)
    fmt.Println(filed1.Tag)
    //top2
    filed2,_:= p1Type.FieldByName("name")
    fmt.Println(filed2.Tag)
    //循环获取
    fieldNum :=p1Type.NumField()
    for index := 0;index<fieldNum;index++{
    field:=p1Type.Field(index)
    fmt.Pringln(field.Name,field.Tag)
    }
    }

3.10 函数

  1. 函数的基本写法

    func 函数名(参数名 参数类型)返回值类型{
    代码块
    return 返回值
    }
    变量 :=函数名(参数值)
  2. 函数做参数

    package main
    import "fmt"
    func add100(arg int)(int,bool){
    return arg + 100,true
    }
    //这种也可以称为起别名。
    type f1 func(arg int)(int,bool)
    func proxy(data int,exec func(int) (int,bool)或f1) int{
    data,flag := exec(data)
    if flag {
    return data
    }else{
    return 9999
    }
    }
    func main(){
    fesult := proxy(123,add100)
    fmt.Println(result)
    }
  3. 接收多个参数

    package main
    import "fmt"
    //可接受多个int类型的参数,
    func do(num...int) int{
    fmt.Println(num)
    return sum
    }
    func main(){
    r1:=do(1,4,5,6)
    fmt.Println(result)
    }
  4. 函数做返回值

    package main
    import "fmt"
    func add100(arg int)(int,bool){
    return arg + 100,true
    }
    type f1 func(arg int)(int,bool)
    func proxy(data int) func(int) (int,bool)或f1{
    pass
    return add100
    }
    func main(){
    fesult := proxy(123,add100)
    result := fesult(145)
    fmt.Println(result)
    }
  5. 匿名函数

    package main
    import "fmt"
    func F1 () func(int) string{
    return func()string{
    return "baba"
    }
    }
    func main(){
    v1 := func() int {
    return 123
    }
    //自执行
    value := func() int {
    return 123
    }()
    }
  6. 闭包

    package main
    import "fmt"
    func main(){
    var functionList []func()
    for i := 0;i<5;i++{
    function := func(arg int)func(){
    return func(){
    fmt.Println(arg)
    }
    }(i)
    functionList = append(functionList,function)
    }
    functionList[0]()
    functionList[1]()
    functionList[2]()
    }
  7. defer

    package main
    import "fmt"
    func do() int{
    fmt.Print(1)
    //defer的效果是延迟执行,函数执行完之后执行。
    defer fmt.Print(2)
    defer fmt.Print(3)
    fmt.Print(4)
    return 666
    }
    func main(){
    ret:=do()
    fmt.Println(ret)
    }

    Type自定义类型,就那么个用法,自己用就行

中阶

1.包

  1. package main
    import (
    "fmt"
    "math/rand"
    "sync"
    )
    var lock sync.Mutex // 互斥锁是只有一个可以进入,释放后才可以进入下一个
    var lock1 sync.RWMutex // 读写锁的读和写是分开的,适合在读多写少的情况使用
    func TestMap(){
    var a map[int]int
    a = make(map[int]int,5)
    a[8] = 10
    a[6] = 10
    a[5] = 10
    a[3] = 10
    for i := 0; i <2;i++{
    go func(b map[int]int){
    lock.Lock() // 上锁
    b[8] = rand.Intn(100)
    lock.Unlock() //释放锁
    }(a)
    }
    lock.Lock() // 只要有读写都需要上锁
    fmt.Println(a)
    lock.Unlock()
    }
    func testRWLock(){
    var a map[int]int
    a = make(map[int]int,5)
    a[8] = 10
    a[6] = 10
    a[5] = 10
    a[3] = 10
    for i := 0; i <2;i++{
    go func(b map[int]int){
    lock1.Lock() // 上锁
    b[8] = rand.Intn(100)
    lock1.Unlock() // 释放锁
    }(a)
    }
    for i := 0; i <100;i++{
    go func(b map[int]int){
    lock1.RLock() // 上锁
    fmt.Println(a)
    lock1.RUnlock() // 释放锁
    }(a)
    }
    }
    func main(){
    testRWLock()
    testMap()
    }

2.SortAnd二叉树

  1. 冒泡排序

    package main
    import("fmt")
    func sort(a []int){
    for i :=0;i < len(a);i++{
    for j :=1;j<len(a)-i;j++{
    if a[j] < a[j-1]{
    a[j],a[j-1] = a[j-1],a[j]
    }
    }
    }
    }
    func main(){
    b := [...]int{2,1,7,234,3,9,3,5,4}
    sort(b[:])
    fmt.Println(b)
    }
  2. 选择排序

    package main
    import("fmt")
    func sort(a []int){
    for i :=0;i < len(a);i++{
    for j :=i+1;j<len(a);j++{
    if a[i] > a[j]{
    a[i],a[j] = a[j],a[i]
    }
    }
    }
    }
    func main(){
    b := [...]int{2,1,7,234,3,9,3,5,4,65}
    sort(b[:])
    fmt.Println(b)
    }
  3. 插入排序

    package main
    import("fmt")
    func sort(a []int){
    for i :=1;i < len(a);i++{
    for j :=i;j>0;j--{
    if a[j] > a[j-1]{
    break
    }
    a[j],a[j-1] = a[j-1],a[j]
    }
    }
    }
    func main(){
    b := [...]int{2,1,7,234,3,96,3,5,4,65}
    sort(b[:])
    fmt.Println(b)
    }
  4. 快速排序

    package main
    import("fmt")
    func sort(a []int,left, right int){
    if left >= right{
    return
    }
    val := a[left]
    k := left
    for i:= left +1;i<= right;i++{
    if a[i] < val{
    a[k] = a[i]
    a[i] = a[k+1]
    k++
    }
    }
    a[k] = val
    sort(a, left, k-1)
    sort(a, k+1, right)
    }
    func main(){
    b := [...]int{2,1,7,234,3,96,3,5,4,65}
    sort(b[:], 0, len(b)-1)
    fmt.Println(b)
    }
  5. 如果每个节点有两个指针分别用来指向左子树和右子树,我们把这样的结构叫做二叉树。

    package main
    import("fmt")
    type Student struct{
    Name string
    left *Student
    right *Student
    }
    func main(){
    var root *Student = new(Student)
    root.Name = "s1"
    var left1 *Student = new(Student)
    left1.Name = "l1"
    root.left = left1
    var right1 *Student = new(Student)
    right1.Name = "r1"
    root.right = right1
    }

3.接口

  1. 方法,go中的方法是作用在特定类型的变量上,因此自定义类型都可以有方法,而不仅仅是struct

    package main
    import "fmt"
    type Student struct{
    Name string
    }
    func (p Student) init(name string){ //定义方法并绑定
    p.Name = name
    }
    func main(){
    var stu Student
    stu.init("stu")
    }
  2. go中当你使用Printf时会自动调用String方法

    package main
    import "fmt"
    type Abc struct{
    Name string
    }
    func (p *Abc) String() string{
    str := fmt.Sprintf("name[$s]",p.name)
    return str
    }
    func main(){
    var a = Abc
    a.Name = "aa"
    fmt.Printf("%s", &a)
    }
  3. 接口,Interface类型可以定义一组方法,但是这些不需要实现。并且Interface不能包含任何变量。

    package main
    import "fmt"
    type Test interface{ // 定义接口
    Print()
    }
    type Abc struct{
    Name string
    }
    func (p *Abc) Print() {
    fmt.Println(p.Name)
    }
    func main(){
    var a = &Abc
    a.Name = "aa"
    a.Print()
    }
  4. 多态,一种事物的多种形态,都可以按照统一的接口执行操作

  5. 接口嵌套,一个接口可以嵌套在另外的接口

    package main
    import "fmt"
    type Reader interface{
    Prad()
    }
    type ReadWriter interface{
    Reader
    }
    type File struct{}
    func(f *File)Read(){
    fmt.Println("asdf")
    }
    func Test(rw ReadWriter){
    rw.Read()
    }
    func main(){
    var f File
    Test(&f)
    }
  6. 类型断言,由于接口时一般类型,不知道具体类型,如果要转成具体类型可以采用有以下方法进行转换

    package main
    import "fmt"
    type Student struct{
    Name string
    }
    func Test(a interface{}){
    b, ok := a.(Student)
    if ok == false{
    return
    }
    fmt.Println(b)
    }
    func main(){
    var b int
    Test(b)
    }
  7. 判断一个变量是否实现了指定的接口

    package main
    import ("fmt")
    type Writer interface{
    Write()
    }
    type ReadWriter interface{
    Writer
    }
    type File struct{
    }
    /*
    func (f *File) Write(){
    fmt.Println("Write data")
    }
    */
    func main(){
    var f *File
    var b interface{}
    b = f
    v, ok := b.(ReadWriter)
    fmt.Println(v,ok) // 你注释后会输出false
    }
  8. 反射:可以在运行时动态获取变量的相关信息。

    package main
    import("reflect")
    reflect.Type0f // 获取变量的类型,返回teflect.Type类型
    reflect.Value0f // 获取变量的值,返回reflect.Value类型
    reflect.Value.Kind // 获取变量的类别,返回一个常量
    reflect.Value.Interface() // 转换成interface类型。

PHP语言

  1. PHP是一种流行的服务器Web程序开发语言之一。PHP特点是语法简单、易于学习、功能强大、灵活易用。

  2. PHP文本预处理语言(PHP:HypertextPreprocessor),是一种HTML内嵌式的语言,与微软的ASP十分相似。

基本认识

  1. 基本语法

    <?php
    // 这是一段php脚本,通过服务器运行生成一个html文件。
    echo "hello world!"; # 向浏览器输出,返回void。
    print("1234"); # 向浏览器输出,返回整型(字符长度)。
    printf("123%d",4); # 和c中的一样。
    sprintf("asdf"); # 将字符串保存在内存中,返回字符串。
    // 单行注释
    /*多行注释*/
    # shell注释
    $asdf=0; # 常见变量并赋值。
    ?>
    <script language="php">
    echo "hello world!";
    </script>
  2. PHP支持的基本数据类型:Integer(整数)、Float(浮点型)、String(字符串)、Boolean(布尔)、Array(数组)、Object(对象)。

    <?php
    $abc=0;
    $sum=123.1;
    $abc=$sum; # 隐式转换类型。
    $abc=(float)$sum; # 强制转换类型。
    $abs=100;
    settype($abs,"string"); # 设置数据类型并返回布尔类型。
    echo gettype($abs); # 查看数据类型并返回字符串
    echo isset($abs); # 判断一个变量是否存在并返回布尔
    unset($abs); # 释放一个变量
    echo empty($abc); # 判断变量的值是否为空并返回布尔。
    is_integer($abc); # 判断一个变量是不是整型并返回一个布尔。is_还可以写别的类型。
    intval($sum); # 转换变量值的类型为整型,不是变量的。也可以称为临时转换.
    floatval($sum);
    strval($sum);
    define("RD",100); # 定义一个常量.
    phpinfo(); # 查看系统默认的常量.
    $_POST["username"]; # 获取表单中的值,使用html编写的表单将其发送到指定php文件,我们使用POST方式去获取,如果你不是POST我是获取不到的.注意:标签记得加name属性.
    ?>
  3. 控制结构

    1. 字符串插入就是字符串的拼接.

      <?php
      $username = "baba";
      echo "nihao $username"; # 有效插入
      echo 'nihao $username'; # 无效插入,单引号可以阻止转义.
      echo "nihao.$username.,wc";
      $sum = $1>2?1:2; # 三元运算.
      echo @(53/0); # 53/0是报错的,我们为了代码可以正常运行,加上@()就可以避免报错.
      ?>
    2. 控制结构

      <?php
      if(条件){
      }else{
      }
      $a =1;
      switch ($a){
      case 1:
      echo "a";
      break;
      case 2:
      ...
      default:
      ...
      }
      ?>
    3. 循环结构

      <?php
      $a=5
      while($a>1){
      echo $a;
      $a--;
      }
      do{
      echo $a;
      $a--;
      if($a===4){
      continue;
      }
      }while($a>1)
      for($a=10;$a<10;$a++){
      echo $a;
      if($a===4){
      break;
      }
      }
      exit; # 退出程序
      ?>
  4. 数学运算

    <?php
    is_numeric("23415"); # 判断是不是数字或数字串.
    echo rand(1,200); # 生成随机数
    echo mt_rand(1,200); # mt_rand比rand的速度快四倍.
    echo getrandmax(); # 获取最大随机数
    echo getmt_randmax(); # 获取最大随机数
    echo number_format(234.132,2,".",","); # 数字字符串
    echo abs(-12);
    floor(234.2) # 舍去法取整
    ceil(123) # 进一法取整
    echo round(123.3);
    echo max(1,2);
    echo min(1,2);
    ?>

1.数组

  1. 传统上把数组定义为一组有某种共同特性的元素.每个元素由一个特殊的标识符来区分,称之为键:而每个键对应一个值.

    <?php
    # 数组是通过下标来取值的.
    $username = array("1,","b","3","6");
    echo $username[1];
    $username[1]="ssdd";
    echo range(1,100); # 范围生成数组
    count($username);
    foreach($username as $key=>$value){
    echo $key.$value # 循环打印数组下标和值.
    }
    # 自定义数组key and value
    $name = array("1"=>"a","b"=>"2");
    echo $name["b"];
    each($name); # 传入一个数组,获取数组的第一个键值,并下移指针.返回一个数组,通过0,1,key,value获取数据.
    reset($username) # 将数组指针调到第一个.
    !!each($name); # 将返回结果转为布尔值.
    list($a,$b,$c)=$username; # list的作用是将数组的值拿出将其赋给变量,只能用于key是数值的数组.
    echo $a;
    print_r(array_unique($username)) # 移除值重复的数据.
    print_r(array_flip($username)); # 调换数组中的键值
    print_r(array(array(1,2),array(1,3))); # 多维数组。
    echo sort($username);
    asort($username); # 保持键值对的关联
    ksort($username); # 按照键排序
    # rsort、arsort、krsort,朝右排序。
    shuffle($username); # 随机打乱数组元素
    array_reverse($username) # 反向排序
    array_unshift($username,"234"); # 开头插入数据
    array_push($username,"45"); # 尾部插入数据
    array_shift($username); # 删除开头的元素
    array_pop($username); # 删除结尾的元素
    array_rand($func,1); # 随机获取数组一个元素下标
    echo current($username); # 获取指针当前元素
    echo next($username); # 指针移动一位。
    echo reset($username); # 指针指向第一个元素
    echo prev($username); # 回溯一位。
    array_count_values($username); # 统计数组中所有的值出现的次数
    echo sizeof($username) # 数组个数
    extract($usename); # 将字符串key转为变量,将值赋值给变量。
    ?>

2.目录和文件

<?php
$path="C:\app.php";
echo "path:".basename($path) # 返回路径的文件名部分
echo "path:".dirname($path); # 返回路径目录部分
echo pathinfo($path); # 创建一个数组,包括目录名、文件名、扩展名。
echo realpath("./app.php"); # 将相对路径转为绝对路径。
echo round(filesize($path)/1024,2)."KB"; # 返回文件字节大小。
echo round(disk_free_space("C:")/1024/1024,2)# 返回指定的目录所有在磁盘分区的可用空间。
echo round(disk_total_space("c:")/1024/1024,2)# 返回指定的目录所在磁盘分区的总容量。
echo date("Y-m-d,h:i:s",fileatime($path)); # 返回文件的最后访问时间,采用的Unix时间戳格式。
echo date("Y-m-d,h:i:s",filectime($path)); # 返回文件的最后改变时间,采用的Unix时间戳格式。
echo date("Y-m-d,h:i:s",filmtime($path)); # 返回文件的最后修改时间,采用的Unix时间戳格式。
$fp=fopen("file.txt","ab"); # 追加并且二进制方式
$outstring = "asdfasdfg";
fwrite($fp,$outstring,strlen($outstring))) # 写strlen()个字节到文件
fgetc($fp) # 读取一个字符,并将指针移动到下一个字符。
fgets($fp) # 读取一行字符,可以指定一行显示的长度
fgetss($fp) # 从文件指针中读取一行并过滤HTML标记
fread($fp) # 读取定量的字符
fpassthru($fp) # 输出文件指针处的所有剩余数据
file($fp) # 将整个文件读入数组中,以行分组。
readfile($fp) # 读入一个文件并写入到输出缓冲
file_get_contents($fp) # 将整个文件读入一个字符串
feof($fp); # 判断文件是否读取完
fclose($fp); # 关闭一个已打开的文件指针。
file_exists("file.txt"); # 查看文件是否存在
filesize("file.txt"); # 查看文件的大小
unlink("file.txt"); # 删除一个文件
rewind(); # 函数可以将文件指针复位到文件的头部
fseek(); # 函数可以以字节为单位报告文件指针当前文件中的位置
ftell(); # 函数可以将文件指针fp从whence位置移动offset字节。
file_put_contents("file2.txt","Tasdf"); # 将一个字符串写入文件。
$fp=fopen("file.txt","ab");
flock($fp,LOCK_EX); # 锁定
# LOCK_SH 读写锁定,文件可以共享,其他人可以读该文件。
# LOCK_EX 写操作锁定,这是互斥的,该文件不能被共享
# LOCK_UN 释放已有的锁定
# LOCK_NB 防止在请求加锁时发生阻塞
$dir = opendir("c:\\"); # 打开路径指定的目录流
echo readdir($dir) # 返回目录中的各个元素
closedir($dir) # 关闭目录流
scandir("C:\\") # 将目录读入数组
rmdir("c:\\") # 删除指定的目录
rename("file.php","newfile.php") # 重命名文件
?>

3.函数

<?php
include"a.php"
include'a.php' # 判断是否包含,如果没有包含就包含一下。
require("a.php"); # 与include相同。
require_once("a.php"); # 判断并确定只包含一次。
$c=11;
function Name($a,&$c){ # 一样
global $d; # 设置全局变量
$GLOBALS["a"]=5; # 设置超级全局变量
$b = $a+1;
echo $c=1122;
return $b;
}
echo Name(345,$c);
echo $c;
# 特殊常量
# __FILE__ 当前文件名
# __LINE__ 当前行号
# __FUNCTION__ 当前函数名
# __CLASS__ 当前类名
# __METHOD__ 当前方法名
?>

4.字符串处理

<?php
$a=" sdf "
chop($a); # 去除字符串后面多余的空格。
ltrim($a); # 去除字符串起始处多余空格
rtrim($a); # 去除字符串后面多余的空格
trim($a); # 去除字符串两边空格。
nl2br("asdfsdfg df \nsdf") # 将字符串中的换行符转为xhtml换行标签。
htmlentities("<strong>adf</strong>"); # 转换所有字符
htmlspecialchars("<strong>asdf</strong>") # 转换特殊字符
strip_tags("<strong>sfd</strong>") # 去掉<strong>
addslashes("asdf\a"); # 所有的引号都加斜杠
stripslashes("asdf\a"); # 去掉这些斜杠
strtoupper() # 字母大写
strtolower() # 字母小写
ucfirst() # 第一个字母大写
ucwords() # 首字母大写
# STR_PAD_RIGHT,STR_PAD_LEFT,STR_PAD_BOTH
str_pad("aaa",10,"1")."is good"; # 将字符串用指定个数的字符填充字符串。
explode('@','ldfjfj@234'); # 字符分割
$array = array("aa","bb","cc");
echo implode(",",$attay);
$tok = strtok("a.s#d,f",'.#,'); # 通过提供的分隔符字符串分割,并下一指针。
while($tok){
echo $tok.'<br />';
$tok = strtok('.#,'); # 不加字符串为上字符分割,加字符串是新字符串分割。
}
echo substr("asdf",1,3); # 分割起点到终点并返回。
print_r(str_split('This is a Teacher!')); # 将字符串按位分割。
echo strrev('This is a Teacher!'); # 可以将一个字符串逆反过来。
echo strcmp("a","b"); # a>b是-1,相等为零,区分大小写。
echo strcasecmp("a","A"); # 不区分大小写,在的和strcmp一样。
echo strnatcmp("2","10"); # 自然排序,就是1大于2这种,非自然排序就是编码自己的排序。这个是自然排序。
echo strspn("123","13467123",1,-1); # 判断字符串在字符串中存在的长度,从第一个位置找到最后一个位置。
echo strlen("asdf"); # 计算字符串出现的长度。
echo substr_count("sdfasfg","c"); # 字符出现的次数。
echo strstr("sdafsgdf","g"); # 从指定的字符串输出到最后一个字符串,不区分大小写.
echo strpos('sadfasdfgdfgas','g'); # 查找字符第一次出现的位置。
echo strrpos('sadfasdfgdfgas','g'); # 查找字符最后一次出现的位置。
echo str_replace("a","e","hallo"); # 替换字符串
echo str_ireplace("a","e","hallo"); # 替换字符串,不区分大小写
echo substr_replace("bbbbbf","asdf",0,5); # 替换字符串,在第三个参数开始替换第二个参数长度到第一个参数,asdfbf。
echo mb_strlen("你好","GBK"); # 指定编码后获取长度。
echo mb_substr("你好",1,1,"GBK"); # 指定编码后取出字符,避免取出其他字符。
echo mb_strstr("sadfg","d","GBK"); # 指定编码后取出指定字符到结尾。
echo mb_strpos("asdfgad","g","GBK"); # 指定编码后获取第一次出现的位置。
echo mb_substr_count("asdfdfsf","d","GBK"); # 指定编码后获取字符出现的个数。
?>

5.正则表达式

  1. 常用的正则表达式

    只能输入数字:"^[0-9]*$"
    只能输入 n 位的数字:"^\d{n}$"
    只能输入至少 n 位的数字:"^\d{n,}$"
    只能输入 m ~ n 位的数字:"^\d{m,n}$"
    只能输入零和非零开头的数字:"^(0|[1-9][0-9]*)$"
    只能输入有两位小数的正实数:"^[0-9]+(.[0-9]{2})?$"
    只能输入有 13 位小数的正实数:"^[0-9]+(.[0-9]{1,3})?$"
    只能输入非零的正整数:"^\+?[1-9][0-9]*$"
    只能输入非零的负整数:"^\-[1-9][0-9]*$"
    只能输入长度位 3 的字符:"^.{3}$"
    只能输入由 26 个英文字母组成的字符串:"^[A-Za-z]+$"
    只能输入由 26 个大写英文字母组成的字符串:"^[A-Z]+$"
    只能输入由 26 个小写英文字母组成的字符串:"^[a-z]+$"
    只能输入由数字和 26 个英文字母组成的字符串:"^[A-Za-z0-9]+$"
    只能输入由数字、26个英文字母或者下划线组成的字符串:"^\w+$"
    验证用户密码: "^[a-zA-Z]\w{5,17}$" 正确格式位:以字母开头,长度在618之间,只能包含字符、数字和下划线
    验证是否含有非法字符 ^(?:[\u4e00-\u9fa5]*\w*\s*)+$
    只能输入汉字:"^[\u4e00-\u9fa5]{0,}$"
    验证 Email 地址:"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"
    验证 InternetURL:"^http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?$"
    中国电话号码验证
    匹配形式如:0511-4405222 或者021-87888822 或者 021-44055520-555 或者 (0511)4405222
    正则表达式 "((d{3,4})|d{3,4}-)?d{7,8}(-d{3})*"
    中国邮政编码验证
    匹配形式如:215421
    正则表达式 "d{6}"
    电子邮件验证
    匹配形式如:justali@justdn.com
    正则表达式 "w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*"
    身份证验证
    匹配形式如:15位或者18位身份证
    正则表达式 "d{18}|d{15}"
    常用数字验证
    正则表达式
    "d{n}" n为规定长度
    "d{n,m}" n到m的长度范围
    非法字符验证
    匹配排除非法字符的字符如:
    正则表达式 ^(?:[\u4e00-\u9fa5]*\w*\s*)+$
  2. 基本使用

    <?php
    $mode = '/php/';
    $string = 'php';
    echo preg_match($mode,$string); # 判断是否匹配
    print_r(preg_grep('/p$/',array('1','2','3'))); # 搜索数组中的所有元素,返回由与某个模式匹配的所有元素组成的数组。
    print_r(preg_match_all('/php[1-6]/','php1adfgphp2',array('1','2','3'))) # 字符串中匹配模式的所有出现,然后将所有匹配到的放入数组。
    echo preg_quote("phpdejiaf:$12"); # 每个对于正则表达式语法而言有特殊含义的字符前插入一个反斜杠。
    echo preg_replace('/php[1-6]/','python','adf asdf adf php4'); # 搜索到所有匹配,然后替换成想要的字符串返回出来。
    print_r(preg_split('/[\.@]/','ydd.com@a.com')); # 以不区分大小写的方式将字符串划分为不同的元素:用来分割不同的元素。
    # 正则表达式中包含三种元素分别为:量词、元字符、修饰符。前导就是前一个字符
    # 量词
    /*
    + 匹配任何至少包括一个前导字符串
    * 匹配任何包括零个或多个前导字符串
    ? 匹配任何包含零个或一个前导字符串
    . 匹配任意字符串
    {x} 匹配任何包含x个前导字符串
    {x,y} 匹配任何包含x到y个前导字符串
    {x,} 匹配任何包含至少x个前导字符串
    $ 匹配字符串的行尾
    ^ 匹配字符串的行首
    | 匹配字符串的左边或者右边
    () 包围一个字符分组或定义个反引用,可以使用\1\2提取。
    */
    # 元字符
    /*
    [a-z] 匹配任何包含小写字母的字符串
    [A-Z] 匹配任何包含大写字母的字符串
    [0-9] 匹配任何包含数字的字符串
    [abc] 匹配任何包含小写字母的字符串
    [^abc] 匹配任何不包含小写字母的字符串
    [a-zA-Z0-9_]匹配任何包含字母数字下划线的字符串
    \w 匹配任何包含字母数字下划线的字符串
    \W 匹配任何没有字母数字下划线的字符串
    \d 匹配任何数字字符
    \D 匹配任何非数字字符串
    \s 匹配任何空白字符
    \S 匹配任何非空白字符
    \b 匹配是否达到了单词边界
    \B 匹配是否没有达到单词边界
    \ 匹配正则中的特殊字符
    */
    # 修饰符
    /*
    i 完成不区分大小写的搜索
    m 在匹配首内容或者尾内容时候采用多行识别匹配
    x 忽略正则中的空白
    A 强制从头开始匹配
    U 禁止贪婪匹配,之跟踪到最近的一个匹配符并结束。
    */
    ?>
    /*
    正则表达式的语法——字符(一)
    数字:\d
    非数字:\D
    空白字符(空格、制表符、换页符等):\s
    非空白字符:\S
    单词字符(26个英文字母+数字+下划线):\w
    非单词字符:\W
    正则表达式的语法——字符(二)
    字符集合:[单个字符或字符区间],用于匹配集合内字符
    比如:
    [a-z]表示a-z这26个小写字母
    [0-9a-z]表示0-9这10个数字和a-z这26个小写字母
    [123a-h]表示包含数字1,2,3和a-h这8个字母
    注意:两个不同的字符段间一定不要用逗号隔开
    非集合字符:[^单个字符或字符区间],用于匹配非集合内字符
    比如:
    [^0-9]表示匹配所有非数字字符
    [^a-zA-Z]表示匹配所有非字母字符
    字符集合的数字区间该注意什么?
    数字区间正则只能匹配0-9的数字,因为正则只能一位一位的匹配,所以超过9以外的数字只是我们给的概念,对于正则机制来说它是认不到的,比如[100-120]就无法被匹配
    正则表达式的语法——关键字
    () 表示一个整体
    ^ 匹配输入字符串的开始位置
    $ 匹配输入字符串的结尾位置
    . 通配符,代表任意字符但不匹配换行
    * 匹配0次或者多次
    + 匹配1次或者多次
    \ 转义字符
    | 两项之间的一个选择
    转义字符“\”的使用
    转义字符主要是将一些特殊字符转为普通字符。而这些常用特殊字符有”.”、”?”、”\”等
    ^和$结合使用的注意问题
    如果^和$结合使用且中间没有其他表达式,那么他们中间就不能出现别的字符,不然无法匹配,比如/^3b$/表示3开头b结尾,所以只有3b才能被匹配,如果写了3acb就无法被匹配。什么情况下才能被匹配呢,可以使用.(通配符)。
    非集合字符的“^”和关键字“^”的区别
    非集合字符的“^”可理解为排除字符,排除操作,一般放在[]中,如[^1-5], 表示该字符不是1-5之间的数字;而关键字的“^”表示行开始,如"^ab"表示以ab开头的字符串。
    正则表达式的语法——限定符
    {n} 例如0{8} 表示只有连起来8个0才会被匹配
    {n,} 例如0{2,} 表示只要2个0及其以上的就会被匹配
    {n,m} 例如0{2,4} 表示最少匹配2个0,最多匹配4个0
    注:被匹配时,默认匹配最多的次数
    正则表达式的语法——修饰符
    i 表示不区分大小写
    A 匹配规则必须从头开始匹配
    s 表示.将匹配一切字符
    x 表示正则表达式中的空白字符会被忽略
    e 代码执行仅限preg_replace()
    匹配模式的优先级是什么?(优先级从高到低排)
    \转义字符;()[]大原子和原子表;*+?{n}{n,}{n,m}重复匹配(匹配次数);^$\b\B边界限制;|模式选择
    */

6.日期和时间

<?php
checkdate(2,29,2007) # 判断是否是有效时间,并返回布尔值。
echo date("Y-m-d H:i:sa") # 返回指定格式的时间。放一个参数是获取当前时间,放两个参数是按指定时间戳返回时间
print_r(gettimeofday()); # 查看更过时间信息,获取当前时间的时间戳
print_r(getdate(1184557366)) # 将时间戳转会为友好的值
echo mktime(14,14,14,11,11,2007) # 获取特定的时间戳:mktime函数可以生成给定日期时间的时间戳
echo time()-(60*60*8) # 获取当前时间的时间戳,按秒计算,可以修改返回的时间。
echo strtotime("2007-10-31 14:31:33") # 将日期转换成时间戳:将人刻度的日期转换为Wnix时间戳。
echo date("Y-m-d H:i:s",getlastmod()) # 获取当前文件最后修改的时间
# 设置时区和GMT/UTC:修改php.ini文件中的设置,找到[date]下的;date.timezone=选项,将该项修改为date.timezone=Asia/Shanghai,然后重新启动apache服务器。putenv()函数可以设置当前的默认时区。
putenv('TZ=Asia/Shanghai');
date_default_timezone_set('Asia/Shanghai') # 可以设置当前的默认时区。
date_default_timezone_get() # 可以获取当前的默认时区。
?>

7.表单与验证

<?php
ob_start(); # 开启缓冲区,不建议开,费资源。
header('Location:http://baidu.com') # 设置html头的跳转,卸载最上面,不然会报错。
header('Content-Type:text/html;charset=utf-8');
# 通过get或post来获取提交到后台的数据。
echo $_GET['name'];
echo $_POST['name'];
echo isset($_GET['name']) # 判断是否获取到了值。
htmlspecialchars()
?>

8.会话控制

<?php
setcookie('name','value',time()+(7*24*60*60)); # 设置cookie
echo $_COOKIE['name']; # 查看cookie
setcookie('name',''); # 删除cookie
?>

9.上传文件

# php.ini
file_uploads=on|off; # 确定服务器上的php脚本是否可以接受文件上传。
max_execution_time=integer; # php脚本在注册一个致命错去之前可以执行的最长时间,以秒为单位。
memory_limit=integer; # 设置脚本可以分配到的最大内存,以MB为单位。这可以防止失控的脚本独占服务区内存。
upload_max_filesize=integer; # 设置上传文件最大大小,以MB为单位。此命令必须小于最大提交数。
upload_tmp_dir = string; # 设置上传文件在处理之前必须存放在服务器的临时的位置,知道文件移动到最终的位置。
post_max_size=integer; # 确定通过post方可以接受的信息的最大大小,以MB为单位。
<form enctype="multipart/form-data" action="upload.php" method="post">
<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
...
</form>
# enctype="multipart/form-data",必须写入这句,不写会上传不成功。
# 隐藏标签加不加都无所谓,但是最后加上,应为php.ini是后端配置的,如果文件很大需要将文件发到后端才可以判断,这样浪费时间而且不高效。
<?php
print_r($_FIELS) # 上传的文件
is_uploaded_file($_FILES["userfile"]["tmp_name"]) # 确认是否上传文件。
move_uploaded_file($_FILES["userfile"]["tmp_name"],$_FILES["userfile"]["name"]) # 移动文件,当你获得到文件后默认是存储到服务器上的临时目录中,移动文件并改名就可以用了。
is_dir("filename") # 判断路径是否存在
mkdir("创建文件夹") # 创建文件夹
?>

10.处理图像

  1. 基本使用

    <?php
    # 第一步,设置文件MIME类型,输出类型改为图像流。
    header("Content-Type:image/png");
    # 第二部,创建一个图形区域,图像背景,返回一个资源句柄
    $im = imagecreatetruecolor(200,200);
    # 第三步,在空白图像区域,绘制颜色
    $blue = imagecolorallocate($im,0,102,255);
    imagefill($im,0,0,$blue);
    # 第四步,绘制蓝色线条
    $white = imagecolorallocate($im,255,25,25);
    imageline($im,0,0,200,200,$white);
    # 第五步,绘制蓝色字体
    imagestring($im,5,80,20,"Mr.Lee",$white);
    # 第六步,输出最终图形
    imagepng($im);
    # 第七步,回收内存资源
    imagedestroy($im);
    ?>
  2. 案例

    <?php
    # 1.验证码
    # 循环生成四个数,每次循环产出一个1到15的数并转为16进制。.=代表加等于自己。
    header('Content-type:image/png');
    for($Tmpa=0;$Tmpa<4;$Tmpa++){
    $nmsg.=dechex(rand(0,15));
    }
    $im = imagecreatetruecolor(75,25);
    $blue = imagecolorallocate($im,0,102,255);
    $white = imagecolorallocate($im,255,255,255);
    imagefill($im,0,0,$blue);
    imagestring($im,5,20,4,$nmsg,$white);
    imagepng($im);
    imagedestroy($im);
    # 2.加载已有的图像
    header('Content-Type:image/png');
    # 获取当前所在文件位置。
    define('__DIR__',dirname(__FILE__).'\\');
    # 在一个url或png文件载入一张新图。
    $im = imagecreatefrompng(__DIR__."222.png");
    $white = imagecolorallocate($im,255,255,255);
    # 只当位置加入水印
    imagestring($im,3,5,5,"http://www.yc60.com",$white);
    imagepng($im);
    imagedestroy($im);
    # 3.加载已有的系统文件
    $text = iconv('gbk','utf-8','李永强');
    $font = 'C:\windows\fonts\simhel.ttf';
    imagettftext($im,20,0,30,30,$white,$font,$text);
    # 4.图像微缩
    header('Content-type:image/png');
    define('__DIR__',dirname(__FILE__).'\\');
    list($width,$height)=getimagesize(__DIR__.'222.png');
    $new_width = $width*0.7;
    $new_height = $height*0.7;
    $im2 = imagecreatetruecolor($new_width,$new_height);
    $im = imagecreatefrompng(__DIR__.'222.png');
    imagecopyresampled($im2,$im,0,0,0,0,$new_width,$new_height,$width,$height);
    imagepng($im2);
    imagedestroy($im);
    imagedestroy($im2);
    ?>

11.连接MySQL

<?php
header('Content-Type:text/html;charset=utf-8');
# 如果报错,加上@号就不报错了,然后使用die将报错信息打印一下。
$conn = @mysql_connect('127.0.0.1:3306','root','123') or die("error".mysql_error());
# 也可以使用常量
define('DB_USER','root');
@mysql_select_db('a') or die('error'.mysql_error());
@mysql_query('SET NAMES UTF8')or die('zfjcw'); # 设置字符集
#
@mysql_query('insert into (name,age) value (li,19)) or die('asdf');
#
$result = @mysql_query('select * from a') or die('asdf');
# 默认是MYSQL_BOTH是关联和数字,MYSQL_ASSOC是关联,MYSQL_NUM是数字。
print_r(mysql_fetch_array($result,MYSQL_ASSOC)); # 输出一条记录;
print_r(mysql_fetch_row($result)); # 从结果集中获得一行作为枚举数组。
print_r(mysql_fetch_assoc($result)); # 从结果集中获得一行作为关联数组。
print_r(mysql_fetch_lengths($result)); # 获取结果集中每个输出的长度
print_r(mysql_field_name($result)); # 获取结果中指定字段的字段名
print_r(mysql_num_rows($result)); # 获取结果集中行的数目
print_r(mysql_num_fields($result)); # 获取结果集中字段的数目
print_r(mysql_get_client_info($result)); # 获取Mysql客户端信息
print_r(mysql_get_host_info($result)); # 获取Mysql主机信息
print_r(mysql_get_proto_info($result)); # 获取Mysql协议信息
print_r(mysql_get_server_info($result)); # 获取Mysql服务器信息。
mysql_free_result($result); # 释放结果及资源
mysql_close($conn); # 断开数据库连接
?>
posted @   無敗の草  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示