Skip to content

Latest commit

 

History

History
786 lines (482 loc) · 19.1 KB

3.md

File metadata and controls

786 lines (482 loc) · 19.1 KB

指针、运算符和位运算

[[toc]]

[toc]

😶‍🌫️go语言官方编程指南:https://golang.org/#

go语言的官方文档学习笔记很全,推荐去官网学习

😶‍🌫️我的学习笔记:github: https://github.com/3293172751/golang-rearn


区块链技术(也称之为分布式账本技术),是一种互联网数据库技术,其特点是去中心化,公开透明,让每一个人均可参与的数据库记录

❤️💕💕关于区块链技术,可以关注我,共同学习更多的区块链技术。博客http://nsddd.top

1.指针

1.1基本介绍

  1. 基本数据类型,变量存的就是值,也叫值类型

​ Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。

 package main
 import "fmt"
 
 func main(){
     var i int = 10    
     Plantln("i的地址是:",&i)
     //熟悉C/C++知道&也是取地址符
 }                            

image-20220106113626488

在内存的情况:

image-20220106113808329

1.2 指针变量

指针变量指向的是一个地址,这个地址指向的空间才是值。

var ptr *int = &i

解释:

  1. ptr是一个指针变量,类型是一个*int类型,==是一个地址==

  2. ptr本身的值是&i

image-20220106114857862

1.3 指针的使用流程

✏️指针的使用流程如下:

  • 定义指针变量。
  • 为指针变量赋值。
  • 访问指针变量中指向地址的值。

⚠️在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。

💡简单的一个案例如下:

package main

import "fmt"

func main() {
  var a int= 20  // 声明实际变量 
  var ip *int     /* 声明指针变量 */

  ip = &a  /* 指针变量的存储地址 */

  //&a和ip是一样的,都是地址
  fmt.Printf("a 变量的地址是: %x\n", &a  )

  // 指针变量的存储地址 
  fmt.Printf("ip 变量储存的指针地址: %x\n", ip )

  // 使用指针访问值 
  fmt.Printf("*ip 变量的值: %d\n", *ip )
}

以上实例执行输出结果为:

a 变量的地址是: 20818a220  #不可预料的地址
ip 变量储存的指针地址: 20818a220
*ip 变量的值: 20

1.4 Go 空指针

当一个指针被定义后没有分配到任何变量时,它的值为 nil

  • nil 指针也称为空指针。
  • nil 在概念上和其它语言的nullNonenilNULL一样,都指代零值或空值。
  • 一个指针变量通常缩写为 ptr。

💡简单的一个案例如下:

package main

import "fmt"

func main() {
  var ptr *int

  fmt.Printf("ptr 的值为 : %x\n", ptr  )
}

以上实例输出结果为:

ptr 的值为 : 0

空指针判断:

if(ptr != nil)     /* ptr 不是空指针 */
if(ptr == nil)     /* ptr 是空指针 */

1.5指针变量的修改

num := 9
var ptr *int
ptr = &num
*ptr = 10      //此时会将num的值修改为1

❤️ 由此可见,golang 相对C语言和c++的指针,相对简单而且容易理解

小方法:

当我们不用包的时候,可以在前面加一个_表示忽略,但是如果你没用到也没有忽略的化,那程序就是报错(前面所写go特性)

package main
import(
	_ "fmt"
	)

2. 值类型和引用类型

  1. **值类型:都有对应的指针类型,形式为 数据形式,比如int 的对应的指针就是 int ,* float32是float对应的指针类型
  2. 值类型包括:基本数据类型 int系统,float系列,bool,string,struct和结构体。
  3. 引用类型:指针,slice切片,map,管道chan,interface等都是

2.1 区别/使用:

值类型:变量可以之间存储值,内存通常在栈中分配

引用类型:变量存储的是一个地址,这个地址对应的空间才是真正存储数据(值),内存通常在堆上分配,当没有任何变量引用这个地址时,这个地址对应的数据空间就成为一个垃圾,由GC回收

image-20220106135200888

eng:内存是由栈区和堆区组成

3. 标识符的命名规范

  1. Golang对各种变量、方法、函数等命名时使用的字符序列称之为标识符
  2. 凡是自己可以其名字的地方都叫标识符

3.1 标识符的命名规范

  1. 二十六个字母组成

  2. 数字不能开头

  3. Golang严格区分大小写

    var num int = 10
    var Num int = 100
    //num 和 Num是不同的变量
  4. 标识符不能有空格,但是可以用__

  5. “__" 本身在Golang中是一个特殊的标识符,表示

    var _ int = 40  //错误
    var a_ai int = 40   //正确
  6. 不能使用系统保留的关键字作为标识符(前面讲过25个标识符)

3.2 标识符命名注意事项

  1. 包名:Golang 每一个go文件 都归属于一个包,包名应该保持和目录尽量一致

  2. 变量名、函数名、常量名:采用驼峰法

    1. 第一个字母小写,第二个字母大写
    2. var goodPrice float32 = 1234.234
  3. ==变量名、函数名、常量名首字母大写,则可以被其他包访问; 如果首字母小写,则只能在本包中使用==(注意❤️ -- 参考其他语言:理解为首字母大写是公开的(pubilc),首字母小写是私有的(private))

    image-20220106142230729

4. Go算数运算符

下表列出了所有Go语言的算术运算符。假定 A 值为 10,B 值为 20。

运算符 描述 实例
+ 相加 A + B 输出结果 30
- 相减 A - B 输出结果 -10
* 相乘 A * B 输出结果 200
/ 相除 B / A 输出结果 2
% 求余 B % A 输出结果 0
++ 自增 A++ 输出结果 11
-- 自减 A-- 输出结果 9

和其他语言相似,不举例。

细节:

  1. 小数问题:

    x := 19/5
    

​ ==此时x=3 ,向下取整==

  1. ==在Golang,++和--只能独立使用==,强制语法统一性和简洁性

  2. 在Golang中,++ 或者--只能写在变量后面,不能写在前面

    var a int =5
    a = i++ //错误,只能独立使用
    a = i-- //错误
    a++  //正确
    ++a  //错误
    
    if i++ > 0{   //错误,在if语句中,非独立使用的
    	fmt.Println("ok")
    }

5. Go关系运算符

关系运算符也称之为比较运算符,常用于流程控制

结果是bool类型,要么是true要么是false

下表列出了所有Go语言的关系运算符。假定 A 值为 10,B 值为 20。

运算符 描述 实例
== 检查两个值是否相等,如果相等返回 True 否则返回 False。 (A == B) 为 False
!= 检查两个值是否不相等,如果不相等返回 True 否则返回 False。 (A != B) 为 True
> 检查左边值是否大于右边值,如果是返回 True 否则返回 False。 (A > B) 为 False
< 检查左边值是否小于右边值,如果是返回 True 否则返回 False。 (A < B) 为 True
>= 检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。 (A >= B) 为 False
<= 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。 (A <= B) 为 True

6. 逻辑运算符

表列出了所有Go语言的逻辑运算符。假定 A 值为 True,B 值为 False。

运算符 描述 实例
&& 逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。 (A && B) 为 False
|| 逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。 (A || B) 为 True
! 逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。 !(A && B) 为 True

和其他语言都差不多🐶🐶🐶

同样的,为||的时候,当左边的为真,就不看右边的了。当为&&时候,左边为假,那么右边也不需要看了

6.1 实例

package main

import "fmt"

func main() {
   var a bool = true
   var b bool = false
   if ( a && b ) { 
      fmt.Printf("第一行 - 条件为 true\n" )
   }   
   if ( a || b ) { 
      fmt.Printf("第二行 - 条件为 true\n" )
   }   
   /* 修改 a 和 b 的值 */
   a = false
   b = true
   if ( a && b ) { 
      fmt.Printf("第三行 - 条件为 true\n" )
   } else {
      fmt.Printf("第三行 - 条件为 false\n" )
   }  o'o 
   if ( !(a && b) ) { 
      fmt.Printf("第四行 - 条件为 true\n" )
   }   
}

测试:

image-20220106145850228

8. 其他运算符

❤️说明:Go语言明确说明不支持三元运算符

其它语言的三元运算符

语法为:条件表达式?表达式1:表达式2

**说明:**问号前面的位置是判断的条件,判断结果为bool型,为true时调用表达式1,为false时调用表达式2。

其逻辑为:“如果条件表达式成立或者满足则执行表达式1,否则执行第二个。”常用在设置默认值,例如某个值不一定存在,则判断这个值是否存在,不存在给默认值(表达式2)。

8.2 Golang三元运算符的实现使用if判断

i := 10
j := 20
if i>j{
	n := i
}else{
	n := j
}
fmt.Paarintln(n)

/*传统编程语言实现:
n = i > j ? i : j
*/

8. 键盘输入

参考第二天的最后笔记

8.1步骤:

  1. 导入fmt包
  2. 调用fmt包的fmt.Scanln() 或者 fmt.Scanf()

💡简单的一个案例如下:

package main
import "fmt"
fun main(){
	var name string
	var age int
	var mf bool
	
	fmt.Println(请输入姓名年龄性别)
	fmt.Scanln(&name)
	fmt.Scanln(&age)
	fmt.Scanln(&mf)
	//方式二
	fmt.Scanf("%s %d %f %t",&name,&age,&mf)
}

9. 进制

9.1 基本的输出方式

%b	表示为二进制
%c	该值对应的unicode码值
%d	表示为十进制
%o	表示为八进制
%q	该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示
%x	表示为十六进制,使用a-f
%X	表示为十六进制,使用A-F
%U	表示为Unicode格式:U+1234,等价于"U+%04X"

9.2 补充python中进制的转换

在ipython模式下的进制转化是我认为最方便的一种

  • 10进制转16进制:hex(10)
  • 10进制转8进制:oct(10)
  • 10进制转2进制:bin(10)
  • 16进制转10进制:int('0x5',16)
  • 8进制转10进制:int('0o5',8)
  • 2进制转10进制:int('0b1100',2)

10 .位运算

位运算符对整数在内存中的二进制位进行操作。

下表列出了位运算符 &, |, 和 ^ 的计算:

p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

假定 A = 60; B = 13; 其二进制数转换为:

A = 0011 1100

B = 0000 1101

-----------------

A&B = 0000 1100

A|B = 0011 1101

A^B = 0011 0001

10.1 实例

package main

import "fmt"

func main() {
   var a int = 21
   var c int 

   c =  a
   fmt.Printf("第 1 行 - =  运算符实例,c 值为 = %d\n", c ) 

   c +=  a
   fmt.Printf("第 2 行 - += 运算符实例,c 值为 = %d\n", c ) 

   c -=  a
   fmt.Printf("第 3 行 - -= 运算符实例,c 值为 = %d\n", c ) 

   c *=  a
   fmt.Printf("第 4 行 - *= 运算符实例,c 值为 = %d\n", c ) 

   c /=  a
   fmt.Printf("第 5 行 - /= 运算符实例,c 值为 = %d\n", c ) 

   c  = 200;

   c <<=  2
   fmt.Printf("第 6行  - <<= 运算符实例,c 值为 = %d\n", c ) 

   c >>=  2
   fmt.Printf("第 7 行 - >>= 运算符实例,c 值为 = %d\n", c ) 

   c &=  2
   fmt.Printf("第 8 行 - &= 运算符实例,c 值为 = %d\n", c ) 

   c ^=  2
   fmt.Printf("第 9 行 - ^= 运算符实例,c 值为 = %d\n", c ) 

   c |=  2
   fmt.Printf("第 10 行 - |= 运算符实例,c 值为 = %d\n", c ) 

}                                                                       
~            

编译:

image-20220106154900081

10.2 原码、补码、反码

image-20220106155507207

❤️注意:在计算机运算的时候,都是以补码的方式来运算的

10.3 golang 中的位运算

::: warning ⚡ 强烈推荐位运算技巧,下面讲的是方法

:::

Go 语言支持的位运算符如下表所示。假定 A 为60,B 为13:

运算符 描述 实例
& 按位与运算符"&"是双目运算符。 其功能是参与运算的两数各对应的二进位相与。 (A & B) 结果为 12, 二进制为 0000 1100
| 按位或运算符"|"是双目运算符。 其功能是参与运算的两数各对应的二进位相或 (A | B) 结果为 61, 二进制为 0011 1101
^ 按位异或运算符"^"是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。 (A ^ B) 结果为 49, 二进制为 0011 0001
<< 左移运算符"<<"是双目运算符。左移n位就是乘以2的n次方。 其功能把**"<<"左边的运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0**。 A << 2 结果为 240 ,二进制为 1111 0000
>> 右移运算符">>"是双目运算符。右移n位就是除以2的n次方。 其功能是把**">>"左边的运算数的各二进位全部右移若干位**,">>"右边的数指定移动的位数。 A >> 2 结果为 15 ,二进制为 0000 1111

image-20220106160251627

💡简单的一个案例如下:

先求补码,再计算

正数的补码与原码相同。负数的补码的符号位为1,其余位为该数绝对值的原码按位取反,然后整个数加1。

image-20220106160800738

package main
import "fmt"

func main(){
	fmt.Parintln(2&3)   //2
	fmt.Parintln(2|3)   //3
	fmt.Parintln(2^3)   //1
}

输出

2
3
1

位移运算:也遵守按照补码计算

a := 1 >> 2  //0
c := 1 << 2  //4
fmt.Println("a=",a,"c=",c)

分析:

c:0000 0001 => 0000 0100 = 4

a:0000 0001 => 0000 0000 = 0

11. 流程控制

❤️❤️❤️ 为了更好的区分理解,这部分将和python一同介绍

程序由上到下逐步执行(参考python交互式脚本语言) ,中间没有任何的判断和跳转。

​ 变量应该先声明后定义,再使用。

11.1 Go分支控制if -else

  1. 单分支

  2. 双分支

  3. 多分支

::: danger 注意❤️ **1. 和C/C++不同,在Golang中就算只写一行代码,也需要有{} **

2. Go中的if还有一个强大之处是在条件判断语句中允许申明一个变量,这个变量的作用域只能在该条件逻辑块内,在其他地方是不起作用的

if age := 20;age > 18{   //在此处定义变量而且可以直接使用 类似于 int i = 0
	fmt.Println("你的年龄是多少啊?")
}

:::

Go 编程语言中 if 语句的语法如下:
if 布尔表达式 {
   /* 在布尔表达式为 true 时执行 */
}
Go 编程语言中 if...else 语句的语法如下:
if 布尔表达式 {
   /* 在布尔表达式为 true 时执行 */
} else {
  /* 在布尔表达式为 false 时执行 */
}

If 在布尔表达式为 true 时,其后紧跟的语句块执行,如果为 false 则执行 else 语句块。

Go 编程语言中 if...else 语句的语法如下:
if 布尔表达式 1 {
   /* 在布尔表达式 1 为 true 时执行 */
   if 布尔表达式 2 {
      /* 在布尔表达式 2 为 true 时执行 */
   }
}

你可以以同样的方式在 if 语句中嵌套 else if...else 语句

但是不建议嵌套过多,尽量控制在三层

案列:

定义两个变量int32 ,判断二者之和,是否能被3又能被5整除,打印提示信息

//定义两个变量int32 ,判断二者之和,是否能被3又能被5整除,打印提示信息

package main
import (
    "fmt"
)
var a int32 = 10
var b int32 = 15
func main(){
    if (a+b)%3==0 && (a+b)%5 ==0{
    fmt.Println("该数符合要求")
    }else{  //注意格式,括号不可随意移位
    fmt.Println("该数木满足要求")
}}     

image-20220106165651385

判断闰年:

if year:= 2019;(year %4 ==0 && year %100 !=0)||year%400 == 0{
	fmt.Println(year,"是闰年")
}  //直接定义

image-20220106170028830

注意:使用数字运算的时候要引入math包进行数字运算

11.2 补充:python分支控制if -else

python语句要注意缩进问题

# -\*- coding: UTF-8 -\*-**   **#****定义中文**

print( "你好,世界" )

 

判断语句

if 判断条件 1:

执行语句1

elif判断语句2执行语句2

else执行语句3

import random :引入随机库

x = random.randint(0,3):表示随机生成0~3数字

In [13]: if x != 90: 
    ...:     print("该随机数并不是理想的") 
    ...: elif x == 80: 
    ...:     print("该随机数就是理想的") 
    ...: else: 
    ...:     i = 10   
    ...:     if i>10: 
    ...:         print("i大于10") 
    ...:     elif i<10: 
    ...:         print("i小于10") 
    ...:     else: 
    ...:         print("i等于10") 
    ...:                                     

image-20220106172510474

END 链接