文章目录

  • 进阶语法
    • 指针
      • 基本指针
      • 高级指针
      • 指针总结
    • 面向对象
      • 概述
        • 对象
      • 结构体
        • 定义与初始化
        • 添加方法
          • 方法的注意事项
          • 类型别名与类型定义的区别
        • 工厂函数
      • 接口
        • 接口声明
        • 接口实现
        • 空接口
        • 类型断言与类型查询
        • 接口总结
      • 面向对象三大特性
        • 封装
        • 继承
        • 多态
  • 欢迎关注我的公众号:编程之路从0到1

进阶语法

指针

基本指针

Go语言虽然存在指针,但是远比C语言指针简单,且Go语言基本指针不能直接进行指针运算。

Go语言基本指针用法和C语言几乎相同

  • & 取地址符
  • * 解引用运算符
func main() {var num int// 声明指向int类型的一级指针 ptrvar ptr *int// 声明指向一个指针的二级指针 pptrvar pptr **int// 取变量地址,赋值给指针ptr = &num // 取指针地址,赋值给二级指针pptr = &ptr// 通过指针修改变量的值*ptr = 10fmt.Printf("num = %d\n", num )fmt.Printf("解引用: *ptr = %d\n", *ptr )fmt.Printf("解引用: **pptr = %d\n", **pptr)
}

人们极容易对值类型引用类型指针类型三个概念混淆,特别是将引用和指针混淆。指针是指一个保存内存地址的变量;而值是指的数据本身,值类型表示这个变量代表的就是数据本身,而不是数据的内存地址。引用则最容易产生歧义的说法,在C++中存在一种引用类型,它表示的是变量的别名,因此C++中的引用和指针是两种不同的类型。而我们在Go中指的引用类型,是指特定的几个类型,分别是slicemapchaninterface,通常它们在内部封装了真实数据的指针,因此这些类型并不是值类型,称呼为引用类型。人们习惯于把指针指向真实数据的内存空间这一现象称呼为引用,即表示对值所在的内存空间的一种引用。

高级指针

为了使Go语言的指针也能像C语言那样能直接操作内存,Go提供了unsafe包,正如其名,它是不安全的,官方不推荐的用法,不到万不得已不建议使用。

unsafe包主要提供了两种类型,三个函数

  • unsafe.Pointer:通用指针类型,主要用于转换不同类型的指针,不能进行指针运算

  • uintptr:主要用于指针运算,uintptr无法持有对象,uintptr类型的目标会被GC回收

函数

  • Alignof
  • Offsetof
  • Sizeof

以上三个函数中,主要说一下Sizeof,它类似于C语言的sizeof运算符,获取一个变量所占据的字节数。

package mainimport ("fmt""unsafe"
)func main() {var price float64var pi float32var num intvar ptr *intptr = &numfmt.Printf("float64 size is %d\n", unsafe.Sizeof(price))fmt.Printf("float32 size is %d\n", unsafe.Sizeof(pi))fmt.Printf("int size is %d\n", unsafe.Sizeof(num))fmt.Printf("*int size is %d\n", unsafe.Sizeof(ptr))
}

打印结果:

float64 size is 8
float32 size is 4
int size is 8
*int size is 8

转化指针,强行进行指针运算

package mainimport ("fmt""unsafe"
)func main() {var arr [5]int = [5]int{1, 2, 3, 4, 5}var p *int = &arr[0]// 将普通指针转为 Pointer类型指针var tmp unsafe.Pointer = unsafe.Pointer(p)// 将Pointer类型转为uintptr后做指针加法运算// 运算完成后,需将uintptr类型重新转为Pointer// 再将Pointer重新转为普通类型 *int指针,最后解引用fmt.Printf("arr[1] = %d\n", *(*int)(unsafe.Pointer(uintptr(tmp) + unsafe.Sizeof(p))))fmt.Printf("arr[2] = %d\n", *(*int)(unsafe.Pointer(uintptr(tmp) + unsafe.Sizeof(p)*2)))fmt.Printf("arr[3] = %d\n", *(*int)(unsafe.Pointer(uintptr(tmp) + unsafe.Sizeof(p)*3)))
}

打印结果:

arr[1] = 2
arr[2] = 3
arr[3] = 4

可以看到,想要在Go语言中进行指针运算,是相当麻烦的,Go语言本身也不建议我们使用指针运算。

另外一定要注意,只有uintptr才能做指针运算,且GC并不把uintptr当做指针,所以uintptr不能持有对象, 它可能会被GC回收, 导致出现无法预知的错误。 而Pointer类型指针指向一个对象时, GC则不会回收这个内存对象

指针总结

  • Go指针主要用于传递结构体地址,防止不必要的内存拷贝,提升性能
  • Go语言使用nil表示空指针
  • Go无需手动管理堆内存,Go编译器会基于逃逸分析来确定内存分配在堆上还是栈上,因此无需对指针进行释放,堆上的内存由GC处理

面向对象

概述

所谓面向对象,是相对于面向过程而言的。那什么是面向过程呢?C语言就是一种典型的面向过程的编程语言。其实过程,也就是所谓的步骤。有一个经典例子是这样的,如何把大象放进冰箱?

  1. 把冰箱门打开
  2. 把大象放进去
  3. 把冰箱门关上

有些人可能会觉得荒诞,大象怎么能放得进冰箱呢?然而这就是面向过程的思维方式,C语言代码如下

void openDoor(){}
void put(void *){}
void closeDoor(){}int main(){// 打开门openDoor();// 放进去put(obj);// 关上门closeDoor();
}

每一个步骤对应到代码其实就是一个函数,每一个函数实现一个功能,然后分步调用这些函数。这些函数可能是我们自己写的,也可能是别人写的,函数实际上是一个黑盒模型,这个盒子是封闭的,我们不知道里面有什么,只知道这个盒子有一个入口和一个出口,就如同ATM机,我们把卡插到入口,另一边出口就冒钱出来了,至于具体的,钱是怎么冒出来的,这不是我们关心的。回到上面的例子,大象能不能放进冰箱,这也不是我们关心的,总之这个函数就是把大象放进冰箱的函数,只管调用它就好了。

有了这种面向过程的思维方式,编程就变得简单清晰有条理了,我们可以先把整个架子先搭起来,所有的函数先空实现,整个架子建好了,再慢慢去实现这一个个函数的具体细节。这跟建房子一样,先把钢结构架子搭起来,然后再慢慢码砖砌墙,最后才是室内装修。

随着软件业的发展,需求越来越复杂,人们发现面向过程的思维模型太简单了,已经无法胜任日益复杂的软件需求了,于是就出现了面向对象的思维方式。面向对象既是一种思维模型,也是一种代码的组织形式。

面向对象核心的载体是类和对象。那什么是类?什么是对象呢?

对象

要说清楚这个问题,得先解释什么是对象,不然还怎么去面向对象呢。在面向对象的哲学里,有一句话是“一切皆对象!”对象一词实际上是从英语翻译过来的,这个翻译其实是不准确的,最重要的就是没有指明这个概念的内涵。它的英文object实际上表达的是具体事物,客观事物,客体的意思。其实就是将具体事物抽象化,用一句星爷电影《功夫》中的台词来解释就是“那个谁”的意思,就是将一切的具体事物,抽象出一个共同的指代模型,你也可以说“那个东西”、“那个事物”,你在说这句话时,一定是指的一个具体存在的东西,而不是一个空泛的虚无的东西,这就是对象的特点。

了解了对象,我们不禁要问,编程中怎么创建对象,怎么运用对象呢?可以试想一下,假设我们现在想要描述猫这种动物,该怎么做?

首先可以观察具体的猫,然后将所有猫都具备的特征提取出来,抽象出来,这个抽象出来的模型也就是。例如,猫都有尾巴,有毛,圆眼竖瞳,喜欢睡觉,昼伏夜出,会抓老鼠,会喵喵叫,喜欢吃鱼等等。这里我们就提取几个特征,形成一个猫类

  • 圆眼竖瞳
  • 有皮毛
  • 吃鱼
  • 抓老鼠
  • 睡觉

有了类,我们就可以判断一只猫是否属于猫类,也可以根据这个类批量创造猫。可以看出,类其实就是一个设计蓝图,或者说是一个模具,所有依据这个蓝图创造的具体的猫都是这个类的一个对象。类就是一个图纸,对象就是这个图纸的具体事物。

类所包含的特征,我们通常分为两种类型,属性和行为。属性是静态的描述,行为是动态的特征。以上面的猫类为例

属性 行为
圆眼竖瞳 吃鱼
有皮毛 抓老鼠
睡觉

行为往往是以动词开头,在编程中用使用函数来表示,而属性则使用变量来表示。纯粹的面向对象编程语言是Java和C#,其次支持面向对象的还有C++和Python等。Go与这些编程语言不同,它没有在语法层面完全支持面向对象,譬如它没有类的概念,Go只能像C语言一样,使用结构体来模拟类,但是Go语言的结构体与C++中的结构体不同,C++的结构体并不是真正的结构体,它实际上就是一个类,C++中结构体与类的差别不大,而Go语言的结构体,更接近C语言的结构体。

结构体

Go语言的结构体类似于C语言的结构体,Go语言使用结构体来模拟类,因此,我们可以简单的将Go的结构体看做是一个类,通过这个结构体生成的也就是该类的对象。

定义与初始化

// 定义学生结构体,即等同于学生类
type Student struct{id uint64name stringage intscore float64
}func main() {// 声明结构体变量 stuvar stu Student// 四种创建结构体对象的型式,即创建对象stu1 := new(Student)stu2 := Student{}// 创建时初始化。按属性顺序初始化stu3 := Student{1001, "Alice", 18, 259.5}// 声明式初始化stu4 := Student{id:1003,name: "Tom", age: 19}// 结构体对象的属性访问与赋值stu2.name = "John"stu2.id = 1002stu4.score = 190.5
}

定义结构体的格式,注意,定义结构体属性时,不要使用var关键字

type 结构体名 struct{字段(属性)
}

在Go语言中,未进行显式初始化的变量都会被初始化为该类型的零值,结构体的属性字段也是一样

另外要注意一点,在C语言中,结构体指针调用成员变量时,使用->操作符,而Go语言中都是使用.操作符,Go语言会对结构体指针做自动转换然后再访问成员

 // 结构体指针pStu := &Student{}pStu.name = "John"// 等价于以下调用。Go会先解引用然后在访问成员(*pStu).name = "John"

添加方法

方法就是一种特殊的函数,对应到面向对象类的概念中,也就是所谓的行为。在Go语言中,方法和函数最显著的区别是多了一个接收者的参数。

package mainimport ("fmt""math"
)// 定义结构体
type Point struct{X,Y float64
}// 为结构体添加SetX方法
func(this *Point)SetX(x float64){this.X = x
}// 为结构体添加SetY方法
func(this *Point)SetY(y float64){this.Y = y
}// 为结构体添加GetDistance方法
func(this *Point)GetDistance() float64{return math.Sqrt(this.X*this.X + this.Y*this.Y)
}func main() {p := Point{3,4}// 使用结构体对象调用方法fmt.Println(p.GetDistance())
}

定义结构体方法格式:

func(接收者)方法名(参数列表) 返回值列表 {}

方法与函数唯一的区别就是多了接收者,它位于关键字func和方法名之间,它的类型就是需要添加方法的结构类型,该参数通常使用结构体指针,参数名任意,不过推荐使用thisself,这里接收者的作用相当于C++中的this指针,或者Python中的self

方法的注意事项

在Go语言中,不仅仅是结构体有方法,所有自定义类型都可以添加方法

// 将int 声明为新类型Integer
type Integer intfunc(this Integer)Add(a int) int{return int(this) + a
}func main() {var num Integer = 21fmt.Println(num.Add(9))
}
类型别名与类型定义的区别

在Go1.9版本中引入了新特性类型别名。在此之前,type关键字只能用于定义新类型,1.9之后,可以用于定义类型别名。

// 定义新类型
type 新类型名 原类型名// 定义类型别名
type 类型别名=原类型名

那么定义新类型和定义类型别名有什么区别呢?

// 定义类型别名
type Integer1=int// 定义新类型
type Integer2 intfunc main() {var num int = 1var a Integer1a = num    //不会报错var b Integer2b = num    //报错
}

类型别名与原类型是完全等同的,而定义的新类型与原类型是不同的,因此将原类型直接赋值给新类型会报错,相应的,定义新类型都可以绑定方法,而使用类型别名则不一定,如上例中,原类型int是不能绑定方法的,因此Integer1也是不能绑定方法的。在C语言中,typedef关键字正是用于定义类型别名的,因此要注意Go语言的区别。

工厂函数

结构体是没有所谓的构造方法的,因此说Go语言的面向对象不是纯粹的面向对象。通常的,可以创建一个名为NewXXX的工厂函数用来专门创建结构体的实例对象。

func NewPoint(x,y float64) *Point{return &Point{x,y}
}

接口

其实接口是我们生活中常接触的概念,最具代表性的是我们手机的充电接口。在智能手机之前的时代,不同的手机都有专用充电器,每一种的插口都是不同的,这给我们生活造成了很大不便,如果一家人出行,得带一大堆充电器,有手机、数码相机、mp3等等电子产品,后来Mini USB接口开始流行,各大电子厂商都遵循这种接口标准,包括按摩仪、剃须刀、电动牙刷等等,从此开始,充电器变得可以通用了,再之后安卓智能手机流行,出现了新的Micro USB接口,到今天仍然是安卓手机最主流的数据、充电接口。目前,新一代手机数据接口type-C也开始逐渐普及。

从上例的物理接口中我们可以得到启示,接口实质上是一种通用的标准或协议,它规范了某种行为特征,而规范接口的好处在于可以即插即用,非常方便。假设手机没电了,我们只需要借一个与手机接口匹配的充电器即可,我们不再关心充电器的具体情况,比如电压、电流等参数,在我们的意识里,只要接口能对上就是可以用的。

实际上,面向对象开发中的所谓接口,其概念正是来自生活中,它的特点跟优势与上例中的物理接口是类似的。Go语言中的接口可以用来定义一组不用实现的方法。如同Java中的抽象方法,C++中的虚函数。与Java等语言不同的是,Go的接口不需要显式的实现。

// 声明接口
type Phone interface{// 声明一个打电话的方法Call(number string)bool// 声明一个发短信的方法SendMessage(number, text string)bool
}// 声明一个结构体,并隐式实现Phone 接口
type HuaWei struct{}func(this *HuaWei)Call(number string)bool{fmt.Println("呼叫:"+number)return true
}func(this *HuaWei)SendMessage(number, text string)bool{fmt.Println("发送给:"+number+"  , "+text)return true
}func main() {// 声明一个接口类型变量 phone var phone Phone// 创建结构体对象h := &HuaWei{}// 通过赋值,初始化接口类型变量phone = h// 使用接口变量调用方法phone.Call("123456")phone.SendMessage("10086","查询话费")
}

我们从手机中抽象出两个功能,分别是打电话和发短信,只要具有这两个功能的电子产品,我们就认为它是手机。声明一个Phone接口,它具有两个空方法CallSendMessage,再定义一个具体的结构体HuaWei,然后给HuaWei结构体绑定两个Phone接口的具体实现方法,这时候HuaWei结构体即隐式的实现了Phone接口,我们就可以说HuaWeiPhone接口的一个具体实现。当然,除了HuaWei还有很多其他品牌手机,我们还可以定义更多不同的结构体来实现Phone接口,总之,只要实现了Phone接口,它就是手机。我们在使用的时候,将具体的结构体对象赋值给接口类型对象,然后使用接口类型对象去调用方法,而不是使用具体的结构体HuaWei的实例对象去调方法。举个例子,当我们需要打电话发短信时,根本不关心具体是什么手机,只要能打出去,能发出去就可以了,这是手机通用的功能,甚至非智能手机都能做到,这种思想也就是面向对象编程中常说的解耦合,通用的功能不要和特定的对象关联起来,如上例中使用具体结构体的h变量调用方法,这就是和特定对象关联了。在Go语言中,正是使用接口来实现解耦合。

接口声明

格式

type 接口名 interface{方法声明1方法声明2
}

注意,接口中的方法声明不需要func关键字,不需要声明接收者,也不需要方法体(不需要花括号),其他的和普通的函数声明一致。

方法名 + 函数签名

接口实现

Go中的接口实现是一种隐式实现,即某个自定义类型中包含全部的接口方法的实现,则这个自定义类型自动实现该接口。因此要注意,除了结构体可以实现接口,通过type关键字创建的新类型都可以实现接口。另外的,一个自定义类型是可以实现多个接口的,只要实现了多个接口的所有方法,它就会自动实现这些接口。

空接口

在面向对象编程中,通常有超类的概念,即所有的类都默认继承某个类,例如Java和Python中Object,而在Go语言中,也有一个所有类型都默认实现的接口——空接口。Go语言目前没有泛型的概念,通常就需要使用空接口来实现类似泛型的功能。

空接口是一个匿名的接口,它不包含任何方法

interface{}

Go语言中的数组和切片只能存放相同的数据类型,我们知道Python中的列表是可以存放任意类型的数据的,那我们如何让数组方法不同的数据类型的元素呢?答案就是借助空接口,声明一个空接口类型的数组

type MyType struct{}// 声明一个interface{}类型的数组,它的长度是5,
objs := [5]interface{}{1,"abc",1.5,[1]int{0},MyType{}}

所有类型都默认实现空接口,包括基本数据类型,这表示所有类型都是interface{}类型的子类型,因此interface{}类型数组就可以装下所有类型的数据。

类型断言与类型查询

假如一个数组或切片是interface{}类型的,那么我们遍历这个数组时,怎么判断该数据的具体类型是什么呢?

在Go语言中,可以使用多种方式判断一个变量的具体类型或是否实现了某接口,这里主要说明一下类型断言与类型查询

类型断言

func main() {objs := [5]interface{}{1,"abc",1.5,[1]int{0},MyType{}}for _,it := range objs{// 类型断言,如何匹配括号中的类型,则ok为trueif o,ok := it.(string); ok{fmt.Printf("string类型:%s\n",o)}if o,ok := it.(int);ok{fmt.Printf("int类型:%d\n",o)}if o,ok := it.(interface{});ok{fmt.Printf("interface{}类型:%T\n",o)}}
}

类型查询

func main() {objs := [5]interface{}{1,"abc",1.5,[1]int{0},MyType{}}for _,it := range objs{// 接口查询,使用switch结构switch v := it.(type){case string:fmt.Printf("string类型:%s\n",v)case int:fmt.Printf("int类型:%d\n",v)case [1]int:fmt.Printf("[1]int类型:%T\n",v)case interface{}:fmt.Printf("interface{}类型:%T\n",v)default:fmt.Println("未知类型")}}
}

接口总结

  • 接口中的方法必须是空实现,没有方法体
  • 接口中不能声明变量
  • 接口不能创建实例,只能通过赋值初始化。赋值对象可以是实现了接口的自定义类型,也可以是一个接口类型
  • Go接口只能隐式实现,即实现接口包含的全部方法
  • 除了结构体,其他任意自定义类型都能实现接口
  • 所有类型,包括基本类型都默认实现空接口
  • 接口是引用类型,其零值为nil

面向对象三大特性

面向对象有三大特性,分别是封装继承多态,如果不能支持这三大特性,那么就不能说这门编程语言支持面向对象。

封装

即将类中抽象出来的属性和对属性的操作封装在一起,并把数据保护在内部,仅对其他包提供有限的操作权限。封装能隐藏实现细节,提供对数据的验证。

我们知道Java有四种包访问权限,C++也有privatepublic,而在Go语言中却并未提供关键字来设置访问权限,它更类似于Python,对包外仅提供可见与不可见两种权限,属性名(包括方法名)首字母大写,则包外可访问,小写则不可访问。Go语言主要通过结构体方法、包访问权限来实现封装特性。大家会发现,Go语言标准库提供的所有函数都是大写字母开头的,这就是为了让包外可访问。相比于其他语言,Go的封装格外别扭。

继承

继承的主要目的就是为了代码复用,更简单说就是为了少写代码,同也更容易构建类与类之间的结构化关系。

type Animal struct{age int
}func(this *Animal)Eat(){fmt.Println("吃东西……")
}func(this *Animal)Sleep(){fmt.Println("睡觉……")
}type Cat struct{Animal // 内嵌匿名结构体表示继承
}func main() {cat := Cat{}cat.age = 10cat.Eat()cat.Sleep()
}

上例中,定义了动物结构体,然后定义Cat结构体,并让它继承于动物结构体,可以看到,在Cat结构体中并未声明age属性,也未绑定任何方法,但是Cat继承了Animal的属性和方法,因此它也具备了这些属性和方法。

当一个结构体与它继承的结构体存在同名属性或方法时,可以使用显式的方式访问

type A struct{Name stringid int64
}type B struct{AName stringnum int
}func main() {b := B{}b.A.Name = "xx"b.Name = "b"b.A.id = 1001
}

Go的结构体也可以多继承,多继承时存在同名字段,可以显式访问

type C struct{AB
}func main() {c := C{}c.A.Name = "xx"c.B.Name = "b"c.B.num = 100
}

除了结构体,接口也可以继承

type A interface{Method1()
}type B interface{Method2()
}type C interface{ABMethod3()
}

如上,C接口继承了AB接口,此时要想实现C接口,就必须将ABC中的方法全部实现

多态

实例对象具有多种形态,可以按照统一的接口来调用多种不同的实现,即面向对象所谓的多态。

Go语言的多态主要体现在两方面,函数参数多态和数组元素多态上面,而数组元素多态,就如同接口一节的interface{}类型数组的例子。

// 声明一个宠物接口
type Pet interface{// 声明一个遛宠物功能函数Walk()
}// 声明猫结构体
type Cat struct{}func(this *Cat)Walk(){fmt.Println("遛猫……")
}// 声明狗结构体
type Dog struct{}func(this *Dog)Walk(){fmt.Println("遛狗……")
}// 声明熊结构体
type Bear struct{}func(this *Bear)Walk(){fmt.Println("战斗民族遛熊……")
}// 定义和宠物一起玩的函数
func PlayWithPets(p Pet){// 调用遛宠物的功能p.Walk()
}func main() {// 声明并初始化一个宠物数组,其元素分别是三种不同的结构体// 这就是多态的数组,实质就是一个泛型数组var pets [3]Pet = [3]Pet{&Cat{}, &Dog{}, &Bear{}}for i := 0;i < 3;i++ {// 函数参数上的多态,传入的实际上是三个不同的结构体对象PlayWithPets(pets[i])}
}

欢迎关注我的公众号:编程之路从0到1

Go语言入门——进阶语法篇(三)相关推荐

  1. Python语言入门这一篇就够了-学习笔记(十二万字)

    Python语言入门这一篇就够了-学习笔记(十二万字) 友情提示:先关注收藏,再查看,12万字保姆级 Python语言从入门到精通教程. 文章目录 Python语言入门这一篇就够了-学习笔记(十二万字 ...

  2. C语言入门Part7--数组篇

    C语言入门Part7–数组篇 **关键字:**数组常见问题及注意事项总结,字符串定义,一维数组在内存中的存储,sizeof()求数组长度的注意事项,sizeof()的用法注意,sizeof()和str ...

  3. FPGA笔记之verilog语言(基础语法篇)

    文章目录 FPGA笔记之verilog语言(基础语法篇) 1. verilog 的基础结构 1.1 verilog设计的基本单元--module 1.2 module的使用 1.3 I/O的说明 1. ...

  4. NAS群晖DSM 进阶教程 篇三:DSM 4458 升级 DSM 4493 update7

    WOW唤醒NAS手机APP: Windows Phone 8.1测试可用"Wake my PC"的详细信息  http://www.windowsphone.com/s?app ...

  5. Xamarin XAML语言教程基础语法篇大学霸

    Xamarin XAML语言教程基础语法篇大学霸 前  言 Xamarin是一个跨平台开发框架.它可以用来开发iOS.Android.Windows Phone和Mac的应用程序.使用Xamarin框 ...

  6. Go语言入门--基础语法

    Go语言入门系列文章目录 Go语言入门–基础语法 Go语言入门–流程语句 Go语言入门–数组和切片 集合(Map)(咕咕咕

  7. c语言圆周率计算_C语言入门这一篇就够了

    c语言入门 C语言一经出现就以其功能丰富.表达能力强.灵活方便.应用面广等特点迅速在全世界普及和推广.C语言不但执行效率高而且可移植性好,可以用来开发应用软件.驱动.操作系统等.C语言也是其它众多高级 ...

  8. 0-c语言入门这一篇就够了-学习笔记(一万字)

    内容来自慕课网,个人学习笔记.加上了mtianyan标签标记知识点. C语言入门 -> Linux C语言编程基本原理与实践 -> Linux C语言指针与内存 -> Linux C ...

  9. c语言for循环除法运算,C语言入门这一篇就够了

    c语言入门 C语言一经出现就以其功能丰富.表达能力强.灵活方便.应用面广等特点迅速在全世界普及和推广.C语言不但执行效率高而且可移植性好,可以用来开发应用软件.驱动.操作系统等.C语言也是其它众多高级 ...

最新文章

  1. 深度学习为什么要resize_为什么要学习演讲与口才
  2. php和python交互-Python如何实现简单的用户交互程序(示例)
  3. 谈一谈Spring-Mybatis在多数据源配置上的坑
  4. spring基于注解的声明式事务控制
  5. 保证全对——2015年第六届蓝桥杯C/C++ B组部分解题报告
  6. 计算机专业408题目结构,2019考研408计算机组成原理知识:计算机系统层次结构
  7. django-查询-F对象-Q对象
  8. lightclients将于4月27日主持召开EIP-3074社区会议
  9. python2.7卸载出问题原因分析_怎么卸载python2.7
  10. rabbitmq视频教程,面试官:
  11. C++(八)— 死锁原因及解决方法
  12. 监管大屏系统_“警视” 警务情指一体大屏可视化决策系统
  13. WES7@IIC-China
  14. 周杰伦 jay《青花瓷》mp3 下载/试听/MV/在线播放
  15. 数据流图、业务流程图、E-R图、系统功能结构图、程序流程图
  16. php拼音首拼,php 实现 汉字转拼音
  17. Android音视频录制类MediaRecorder用法举例
  18. 201771010112罗松《面向对象程序设计(java)》第十七周学习总结
  19. 服务器带宽打开网页很慢,为什么网速很快,但打开的网页速度却很慢?
  20. 算法题--递归解法(化整思想、24点、全排列、单词迷宫解法加步骤)

热门文章

  1. linux下不卸载nginx安装第三方模块
  2. Java版本飞机大战
  3. Linux常用环境配置及软件安装(持续更新)
  4. 国有企业不能有信息化
  5. Linux痕迹清除技术
  6. python爬取腾讯新闻_python爬虫实战――爬取腾讯新闻 !
  7. SA168 3BSE003389R1
  8. CoreException: Could not get the value for parameter
  9. vue-pdf预览乱码问题、打印乱码多一页空白问题
  10. php框架 postgresql,CodeIgniter框架中使用PostgreSQL的配置