几种语言实现同一个功能的代码对比

前言

正准备写一篇关于推荐用C作为入门语言的文章《关于程序员的入门语言》,其中一个论点是:

C语言的语法跟Java、JavaScript、PHP等很像,甚至可以说是后者们的基础。

因为要贴出代码,篇幅较长,所以将其独立成一篇,正是此文。

〇、功能要求描述

要求:

对给出的一个字符串,将其中的空格去掉,大写字母变小写。
例如,”HELLO, world.”(13个字节)的转换结果是”hello,world.”(12字节)。

一、几种语言的代码实现

以下是C、Java、JavaScript、PHP、Python等的实现代码。

注:全部代码在 macOS 10.13 上运行通过。

C语言实现

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

int convert(char *text, char* buffer, int bufferSize) {
    char *p;
    
    int count = 0;
    for (p = text; *p != '\0'; p++) {
        if (*p != ' ') {
            buffer[count++] = tolower(*p);
            
            if (count >= bufferSize) {
                break;
            }
        }
    }
    
    return count;
}

int main(int argc, char *argv[]) {
    char *target = "HELLO, world.";
    char *buffer;
    
    #define BUF_SIZE 128
    buffer = malloc(BUF_SIZE); // 假定缓冲区大小足够
    
    // convert
    int size = convert(target, buffer, BUF_SIZE - 1); // 减1以预留给 '\0'
    buffer[size] = '\0'; // 须显式地结束字符串
    
    // output
    printf("%s\n", buffer);
    printf("%d\n", size);
    
    free(buffer); // 释放内存
    
    return 0;
}

C99标准

Java实现

class Convert {
    public static String convert(String text) {
        StringBuilder sb = new StringBuilder();
        
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            if (c != ' ') {
                c = Character.toLowerCase(c);
                sb.append(c);
            }
        }
        
        return sb.toString();
    }
    
    public static void main(String[] args) {
        String target = "HELLO, world.";
        
        // convert
        String output = convert(target);
        
        // output
        System.out.println(output);
        System.out.println(output.length());
    }
}

Java 8

JavaScript实现

function convert(text) {
    var buffer = '';
    var i;
    var c;
    
    for (i = 0; i < text.length; i++) {
        c = text[i];
        if (c != ' ') {
            buffer += c.toLowerCase();
        }
    }
    return buffer;
}

var target = "HELLO, world.";

// convert
var output = convert(target);

// output
console.log(output);
console.log(output.length);

Node.js v9.4.0
注:后文有更简洁的实现

PHP实现

function convert($text) {
    $buffer = "";
    
    for ($i = 0; $i < strlen($text); $i++) {
        $c = $text[$i];
        if ($c != ' ') {
            $buffer = $buffer . $c;
        }
    }
    
    return $buffer;
}

$target = "HELLO, world.";

// convert
$output = convert($target);
// output
echo $output . "\n";
echo strlen($output);

PHP 7

Python实现

def convert(text):
    buffer = ''
    for x in text:
        if x != ' ':
            buffer += x.lower()
    return buffer

target = "HELLO, world."

# convert
output = convert(target)

# output
print(output)
print(len(output))

Python 3.6
注:后文有更简洁的实现

二、语言间异同和知识点

通读上述代码,你就会发现,除了Python外,Java、JavaScript和PHP在语法上跟C是很像的,当然也有不同的地方。

当你熟悉了这些异同后,就很容易学习和掌握C之外的几种语言了。

二.1. 相同点

  • 字符串都是以类似于数组的形式存在,可以遍历(iterating);
  • 定义函数,以及函数的参数、返回值的方式比较接近;
  • 条件判断(if、!=等)几乎一样;
  • for语法几乎一样;
    • C之外的几种语言支持for的变种(如for…in,forEach等),以便更方便地遍历Array, List, Map, Set等;
    • 出了for, while, switch等基本上是一样的(Python没有switch);
  • 都支持+=赋值方式,几乎都有++运算符(Python没有);
  • (除Python外),都是使用花括号({ / } )定义控制类、函数、程序块等的边界,都是使用分号(;)来结束一行语句(JavaScript支持不写分号,具体是否不写分号,就见仁见智了) — 语法何其相似呀。

二.2 不同点

  • C和Java是“静态类型语言”(Statically Typed Language),就是说,对于变量、函数参数、函数返回值,你都必须在声明(declaration)时指定它们的类型,编译器在编译时会进行检查。
    • 相应地,JavaScript、PHP、Python等则是“动态类型语言”(Dynamically Typed Language)
    • JavaScript的变量需要用var来定义,函数参数就不需要了;
    • PHP的变量、参数的前面都需要加美元符号($);
    • Python类似于PHP,但不需要加美元符号($);
    • 概括来说,你可以说C和Java中用的是“变量”(Variables)(一般指在内存中位置相对固定,且有明确类型),而JavaScript、PHP、Python中用的是“名字”(Names)或者“符号”(Symbols),以此区别于“变量”;
  • C语言的字符串是char数组或者char指针,C没有专门的“字符串”类型
    • 所以对C对Unicode的支持不够友好,其他几种语言的新版本对Unicode都提供了built-in的支持—-这一点在本文中暂不深入讨论;
    • C的char是8-bit的,而Java的char是16-bit的;
    • 其他几种语言对字符串都做了或多或少的封装,且基本上要求“字符串一旦生成即再不可变”—-这一点会消耗一定的内存和计算,但因为在一定程度上减少了因为“可变性”(mutability)带来的bugs – 这一点有点Functional Programming(函数式编程)的意味,可独立成篇;
    • 因为Java中的字符串是不可变的,所以出于性能考虑,Java提供了StringBuilder – 先开辟一片内存然后通过append来追加,而不是“生成新String然后丢弃旧String”,从而降低了“垃圾回收”(GC)的负担;
  • C语言需要程序员管理内存的长度计算、申请、释放,而其他语言则自行管理内存;
    • C的例子中,因为buffer是显性malloc出来,然后传给convert函数的,所以convert函数里面需要检查,不能“越界访问”,所以每次填入一个字符就要判断是否越界(count >= bufferSize);
    • 其他几种语言,自行管理内存的申请、释放 – 当然,在上述例子中,它们都存在性能较差的问题(Java好一些,因为用到了StringBuilder从而较少了“中间临时字符串”对象的生成和释放);
    • 其他几种语言自动释放内存的机制各不相同,本文不深入讨论;

三、总结

看了上面的 代码样例 和 异同点比较,相信(希望😊)你已经对C语言必要性有了深一步的认识。

这里需要指出的有:

  • 其他几种语言虽然语法上比C更高级,编程时可以忽略很多细节(更加专注于What to do而不是How to do),但底层中,要做的还是要做的(例如,遍历数组、分配内存、所分配的内存不足时需要重新分配)- 这涉及到性能问题 — 虽然编程时不一定涉及,但思考时需要知道这细节
  • Unicode字符串、字符编解码等归根结底,在内存和磁盘上都是以byte数组、序列的形式存在(一个中文字符以UTF-8编码时一般占3个bytes,有些占4个bytes;内存的操作归根结底也是byte数组 — 学习C可以让你更好地理解内存、指针、引用等,从而为掌握其他语言、对象生命周期等打好坚实的基础;

另外,C语言的编译、链接过程也是值得学习和掌握到一定程度的,因为这对学习Java的Ant、Maven,或者JavaScript的WebPack等是有一定的指导意义的。

四、更优雅的实现

以下是使用JavaScript和Python的更优雅实现(均可以合并为“一行”语句),颇有Functional Programming(函数式编程)的味道—-具体指的是,以“描述需要做的处理”,且可“串联”起来,一般不涉及中间变量等。

  • 请跟上面的C例子对比一下,感受一下What to do和How to do的“开发效率”的差异。

JavaScript

var target = "HELLO, world.";

// convert
var output = target.split('')
    .filter( c => c != ' ') // 箭头函数。见“参考”中的链接
    .map(c => c.toLowerCase())
    .join('');

// output
console.log(output);
console.log(output.length);

Node.js v9.4.0

Python

target = "HELLO, world."

# 使用 `List Comprehension` - 见“参考”中的链接
output = [c.lower() for c in target if c != ' ']
output = ''.join(output)  # list to string

print(output)
print(len(output))

Python 3.6

参考

    原文作者:冯阿良
    原文地址: https://www.jianshu.com/p/69a9bef93a99
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞