# 简介

  • 程序:本质上是一组计算机指令代码,能让计算机执行某种操作。
  • 编程:泛指编写计算机程序的过程。
    • 编写程序代码之后,再执行程序代码,即可控制计算机完成某些任务。
  • 编程语言:泛指可用于编写程序代码的语言。

# 语言分类

# 机器、汇编、高级

将编程语言根据可读性分类:

  • 机器语言
    • :由二进制代码 1 和 0 组成,几乎没有可读性。
    • 能直接被计算机识别、执行,但是不能移植到不同操作系统上运行。
  • 汇编语言
    • :用助记符编写程序,又称为符号语言。有基本的可读性,但是仍然难以记忆。
    • 汇编语言编写的代码要通过汇编(即翻译)转换成机器语言才能运行。
  • 高级语言
    • :模仿自然语言的语法进行编程,可读性好。
    • 与高级语言相比,机器语言和汇编语言都是低级语言。

# 编译、解释、脚本

将编程语言根据运行方式分类:

  • 编译型语言
    • :代码通过编译器(先翻译再执行)转换成机器语言之后才能运行。比如 C、C++ 语言。
    • 缺点:程序在编译之后几乎不能移植。
  • 解释型语言
    • :代码不需要编译,在运行时才通过解释器(边翻译边执行)转换成机器语言。比如 Java、C# 语言。
    • 优点:程序容易移植到不同平台。
  • 脚本语言
    • :属于解释型语言、动态语言。比如 Shell、Python 语言。
    • 优点:可以不编译就即时执行代码,可以逐行执行代码,便于调试。
    • 一般而言,编译型语言、解释型语言、脚本语言的运行速度、效率依次递减。
    • 脚本语言刚诞生时功能较少,如今已经进化得像编译型语言一样功能强大。而且现在计算机硬件性能提升了很多,使用脚本语言也可以达到很好的性能。

# GPL、DSL

将编程语言根据使用场景分类:

  • 通用编程语言(General Purpose Language ,GPL)
    • 可用于多种领域,用途较广。
  • 领域特定语言(Domain Specific Language , DSL)
    • 主要用于个别领域,但在该领域的使用效果可能比通用编程语言更好。
    • 例如用于描述 Web 页面的 HTML、CSS 语言,用于数据库结构化查询的 SQL 语言,用于匹配字符串的正则表达式,用于 Linux 终端操作的 Shell 语言。

# 语法分类

# 弱类型、强类型

根据变量赋值、运算时,能否自动转换数据类型来分类:

  • 弱类型
    • :支持自动转换数据类型。
    • 例如在 C 语言中可执行以下语句:
      float x = 1;
      
  • 强类型
    • :不支持自动转换数据类型。
    • 一种编程语言可能同时具有强类型、弱类型的语法。例如在 Python 中:
      >>> x = 1
      >>> x = '1.0'   # 同一个变量可以执行不同类型的赋值,这是因为改变了变量引用的对象,体现了 Python 是动态类型语言
      >>> 1 + '1.0'   # 不同类型的值不支持混合运算,体现了 Python 是弱类型语言,但用户可以重载 __add__() 方法来实现混合运算
      TypeError: unsupported operand type(s) for +: 'int' and 'str'
      

# 静态类型、动态类型

根据程序运行时,能否改变变量的数据类型来分类:

  • 静态类型语言(statically typed language)
    • :在程序编译之后,变量的数据类型不能改变。
    • 通常在程序编译时就检查数据类型,如果数据类型不符合要求,则中断编译,并报错。
  • 动态类型语言(dynamically typed language)
    • :在程序编译之后,变量的数据类型可以改变。
    • 通常在程序运行时才检查数据类型,如果数据类型不符合要求,可能报错,也可能自动转换数据类型。
    • 优点:使用变量时可以很灵活。
    • 缺点:数据类型不符合要求时,如果不报错,导致问题被用户忽略,则可能引发更大的问题。

# 静态编程、动态编程

根据程序运行时,能否改变程序结构来分类:

  • 静态编程语言(dynamic programming language)
    • :在程序编译时确定了程序结构,不能改变。
    • 简称为静态语言。大部分静态语言属于静态类型语言。
  • 动态编程语言(dynamic programming language)
    • :在程序运行时可以改变程序结构,比如改变函数、改变代码。
    • 简称为动态语言。大部分动态语言属于动态类型语言。
    • 鸭子类型(duck typing):如果一只鸟走起来像鸭子,游起来像鸭子,叫起来也像鸭子,那它就是一只鸭子。
      • 鸭子类型体现了动态语言的特点:只要一个类提供了鸭子类该有的属性和方法 walk()、swim()、quack() ,就可以将它当作一个鸭子类使用。

# 编程范式

编程范式(Programming Paradigms):泛指编写代码的风格。有的编程语言的语法较少,只支持少量几种编程范式。

# 面向过程编程

:Process-oriented Programming 。指按解决问题的流程,一步步编写代码。

  • 这样编写的程序,会让 CPU 按顺序执行一行行指令。也可以将多行指令,封装为一个函数,然后调用该函数。

# 面向对象编程

:Object Oriented Programming(OOP)。指将实现某一功能的相关变量、函数,封装为一个类。

  • 优点:
    • 代码容易复用。使用同一个类,可以创建多个相似的对象,不必为每个对象分别编写一套代码。
    • 可扩展性好。假设某个功能由某个类实现,如果想修改该功能,不必修改该类的源代码,可以继承该类,定义一个子类。
  • 缺点:
    • 开销更大。使用每个类时,必须先实例化,创建一个对象,分配一定内存。
    • 同一个类的多个方法之间通常耦合,具有继承关系的多个类之间通常耦合,需要理清它们的耦合关系。
  • 例:
    • C 语言通常是编写函数,进行面向对象编程。也可以用 struct 结构体,进行面向对象编程,不过缺少继承、多态等语法。
    • Java 语言支持多种面向对象的语法,擅长面向对象编程。类中的每个方法,相当于一个函数,属于面向过程编程。
  • 现代的高级语言,大多支持面向对象编程,提供了三种基本语法:
    • 封装
      • 将实现某一功能的相关变量、函数,封装为一个类,从而集中到同一个命名空间,方便相互调用。
      • 封装,有利于实现高内聚、低耦合的设计模式。
      • 类中的函数,通常称为方法(method)。
      • 类中的变量、函数,统称为该类的成员(member)。
    • 继承
      • 定义一个类时,允许继承另一个类的变量、函数,而不必将另一个类的源代码拷贝到当前类。
    • 多态
      • 同一个类中,允许几个方法的名称相同,但源代码、实现的效果不同。

# 结构化编程

:Structured Programming 。指编程时采用顺序、选择、循环、递归等流程结构。

  • 早期的编程语言,只支持面向过程编程,只能按顺序从上到下执行代码。虽然可以用 goto 跳转执行代码,但容易引发 bug 。
  • 后来的编程语言,提供了多种流程结构。例如 if 语句属于选择结构,if 语句中的语句块可以包含多条语句,属于顺序结构。

# 函数式编程

:Functional Programming 。编写函数时像编写数学函数,主要考虑给定输入参数时返回什么值,不会主动影响函数外部,不会影响程序的行为。

  • 优点:使函数高度解耦,常用于声明式编程。

# 符号式编程

:Symbolic Programming 。可以定义实现某种功能的表达式。

  • 与函数相比,这样的代码更接近数学表达式,更直观。
  • 例如 Lisp 语言中用表达式 (+ 1 2) 来求和,而不是函数 sum(1, 2)

# 命令式编程

:Imperative Programming 。擅长向计算机发出各种指令。

  • 例如 shell 脚本语言,提供了 mv 指令来移动计算机中的文件,不需要用户亲自编写一段代码来移动文件。

# 声明式编程

:Declarative Programming 。只管描述用户想得到什么结果,不考虑具体过程怎么做。

  • 例如 SQL 语言,只管描述用户想从数据库获取什么数据,不管如何获取该数据。
  • 例如正则表达式。

# 元编程

:Meta Programming 。指程序运行时可以修改自己或其它程序的代码。

  • 所有编译器、解释器、DSL 都属于元编程,一般语言的反射、泛型也属于元编程。

# 相关概念

# 耦合度

:Coupling ,指两个代码之间的联系深浅,影响它们能否独立运行。

  • 假设程序 A 运行时,必须调用程序 B ,则它们的耦合度高。
  • 假设程序 A 运行时,可以调用程序 B ,也可以不调用,则它们的耦合度低。
  • 在模块化编程时,应该尽量降低耦合度,便于随时更换模块,提高可扩展性。

# 语法糖

:Syntactic Sugar 。泛指一些提升代码的可读性的语法,但不一定能优化程序的运行效率。

  • 例如 Python 中的列表推导式。