最好的编程语言(如何不再担忧,爱上代码)




原文:The Best Programming Language (or How to Stop Worrying and Love the Code) by A. Castro-Castilla

每隔一段时间,就会有人觉得是时候再写一篇帖子讲讲什么编程语言最好,某个古老语言有什么强大的特性,或者哪个新语言做对了。现在,轮到我来写了。我终于能说说我对编程语言的看法了。

首先,免责声明:除非你用过30多种语言,而且受过他人写的所有这些语言(或者大部分)的代码的折磨,否则你就称不上是客观的。所以是的,我有偏向,就像讨论这个话题的大多数人一样。实际上我相信,一旦精通多种语言,这个话题就会显得荒诞。
给懒得读的人:伟大的语言
我特此在本博客范围内宣布以下语言为伟大语言。
  • Assembly:机器的语言。
  • C:系统开发的语言。
  • Javascript:网络的语言。
  • Scheme:轻巧、可嵌入而且极为灵活的语言,可以经编译转化为C和Javascript。
大部分代码例子来自 Rosetta Code

适用的语言

我把这些语言称作适用的语言,不是因为他们最好。他们只是当今最常用的语言,因此适用于生产性软件。当然,你可以略过争议,凭直觉做决定。如果是这样,请看下一节。

Ada

我一直对围绕存储安全设计软件这个概念感兴趣。对实时操作系统和各种关键系统中的应用程序而言,这都是个可行的概念。如果你在考虑使用这种语言,你很可能有相当的专业背景,不需要读这个帖子。这种语言是成为高手之后用的语言,而那时候也没有多少选择了。一些Ada代码:

  1. function Best_Shuffle(S: String) return String is  
  2.    T: String(S'Range) := S;  
  3.    Tmp: Character;  
  4. begin  
  5.    for I in S'Range loop  
  6.       for J in S'Range loop  
  7.          if I /= J and S(I) /= T(J) and S(J) /= T(I) then  
  8.             Tmp  := T(I);  
  9.             T(I) := T(J);  
  10.             T(J) := Tmp;  
  11.          end if;  
  12.       end loop;  
  13.    end loop;  
  14.    return T;  
  15. end Best_Shuffle;  
   function Best_Shuffle(S: String) return String is
      T: String(S'Range) := S;
      Tmp: Character;
   begin
      for I in S'Range loop
         for J in S'Range loop
            if I /= J and S(I) /= T(J) and S(J) /= T(I) then
               Tmp  := T(I);
               T(I) := T(J);
               T(J) := Tmp;
            end if;
         end loop;
      end loop;
      return T;
   end Best_Shuffle;

看着就很安全,对吧?:)


Bourne (Again) Shell

我经常想:我真的需要用shell语言写这个Linux脚本吗?真的有必要吗?不用shell写脚本也没关系,因为你迟早得面对面处理这种脚本,然后不禁疑惑在没有stackoverflow.com的裸金属时代,这是怎么写出来的。总之,有合适的书指导,你会发现这种语言只是需要一点修饰(和一致性)。这种语言没什么出色的地方,不会开阔视野、提高效率,业务角度也没有什么可取之处,它只是横行Unix和类Unix的世界。然而不管怎么说,它在系统管理中不可或缺,而且并没有看起来那么差。它有点像Javascript,比起其他语言,需要知道更多的实用规范。
我用Unix Shell做什么?
  • OSX/Linux/POSIX系统管理
  • 任务自动化
  • 解锁命令行的强大功能
以下是一点Bourne Shell代码。欣赏这些boolean表达式吧!

  1. #!/usr/bin/env sh  
  2.   
  3. l="1"  
  4. while [ "$l" -le 5 ]  
  5.   do  
  6.   m="1"  
  7.   while [ "$m" -le "$l" ]  
  8.     do  
  9.     printf "*"  
  10.     m=`expr "$m" + 1`  
  11.   done  
  12.   echo  
  13.   l=`expr "$l" + 1`  
  14. done  
#!/usr/bin/env sh

l="1"
while [ "$l" -le 5 ]
  do
  m="1"
  while [ "$m" -le "$l" ]
    do
    printf "*"
    m=`expr "$m" + 1`
  done
  echo
  l=`expr "$l" + 1`
done


就算你不喜欢C,也不得不尊敬它。它可以说是最伟大的语言之一。它能真正地能编写机器级代码(而不是其模型)。它是UNIX之父,是所有类C语言的鼻祖,是系统开发界的通用语。它久经沙场,经历时间的检验,广泛传播。太多的开发,调试,性能分析工具支持着C的发展,这也减少了它作为语言的缺陷(在我看来,缺陷不多)。这是一个真正实现了其目标的语言:适用于所有处理器的万用汇编语言。今天,它甚至能在最奇怪的体系结构中胜任实际上的汇编语言,与C编译器产生的代码相比,要手写出更好的代码十分困难。
因此,C是一个强大的工具,但要掌握好它可不容易。这种语言冷酷无情,你得十分清楚自己在干什么。正因为如此,C语言是教人理解机器的语言。这里面有美妙之处,也有实用的一面:如果没有C语言提供的底层功能,有些事情就没法实现。C语言程序员必须彻底理解自己在干什么,长远来看,这使得他们能产出高度可靠的软件。如果有种语言能影响C语言的神圣地位,那一定是一种很好地支持并发的低级语言,或者是性能如Haskell、风靡如C语言的神一般的语言。
Linux内核中的一些C语言代码

  1. int next_pidmap(struct pid_namespace *pid_ns, unsigned int last)  
  2. {  
  3.     int offset;  
  4.     struct pidmap *map, *end;  
  5.   
  6.     if (last >= PID_MAX_LIMIT)  
  7.         return -1;  
  8.   
  9.     offset = (last + 1) & BITS_PER_PAGE_MASK;  
  10.    map = &pid_ns->pidmap[(last + 1)/BITS_PER_PAGE];  
  11.    end = &pid_ns->pidmap[PIDMAP_ENTRIES];  
  12.    for (; map < end; map++, offset = 0) {  
  13.        if (unlikely(!map->page))  
  14.            continue;  
  15.        offset = find_next_bit((map)->page, BITS_PER_PAGE, offset);  
  16.        if (offset < BITS_PER_PAGE)  
  17.            return mk_pid(pid_ns, map, offset);  
  18.    }  
  19.    return -1;  
  20. }  
int next_pidmap(struct pid_namespace *pid_ns, unsigned int last)
{
    int offset;
    struct pidmap *map, *end;

    if (last >= PID_MAX_LIMIT)
        return -1;

    offset = (last + 1) & BITS_PER_PAGE_MASK;
   map = &pid_ns->pidmap[(last + 1)/BITS_PER_PAGE];
   end = &pid_ns->pidmap[PIDMAP_ENTRIES];
   for (; map < end; map++, offset = 0) {
       if (unlikely(!map->page))
           continue;
       offset = find_next_bit((map)->page, BITS_PER_PAGE, offset);
       if (offset < BITS_PER_PAGE)
           return mk_pid(pid_ns, map, offset);
   }
   return -1;
}


C++

怪物。它是我接触的第一种语言,直到尝试了许多其他语言后,我才明白它多么严重地影响我的效率,限制我的技术。一些著名的程序员对C++评价甚低,对此我完全赞同。C++像是Bjarne Stoustrup把他能想到的所有的功能都加到C中的成果。掌握C++耗费精力巨大,可能使编程效率降低80%以上。这样想吧:你的大脑容量是X,容量有限,不管你有多少的能力,都应该尽可能为重要的事情留出空间。明智的做法是少在语言本身上用脑力,大部分用来解决问题,编写算法。如果语言复杂,无论你有多聪明,都要在语法和语义上花费更多脑力,而不能专注于用代码实现你的想法。
    我认为C++是高难度低收益的典型例子。我同意,用C语言编写大的程序很困难(但依然可能,看Linux内核)。从各方面看Go,Rust和D语言都更好,但事实是C++在世界范围内被广泛应用。
下面是一个优秀C++代码的例子,使用了模板。C++代码中像这样的用户代码段比模板或者类的定义好懂的多。

  1. #include <fstream>  
  2. #include <string>  
  3. #include <iostream>  
  4.   
  5. int main( int argc , char** argv )  
  6. {  
  7.     int linecount = 0;  
  8.     std::string line;  
  9.     std::ifstream infile( argv[ 1 ] );  
  10.     if( infile )  
  11.     {  
  12.         while( getline( infile , line ) )  
  13.         {  
  14.             std::cout << linecount << ": " << line << '\n';  
  15.             linecount++;  
  16.         }  
  17.     }  
  18.     infile.close();  
  19.     return 0;  
  20. }  
#include <fstream>
#include <string>
#include <iostream>

int main( int argc , char** argv )
{
    int linecount = 0;
    std::string line;
    std::ifstream infile( argv[ 1 ] );
    if( infile )
    {
        while( getline( infile , line ) )
        {
            std::cout << linecount << ": " << line << '\n';
            linecount++;
        }
    }
    infile.close();
    return 0;
}

然后是模板代码,这个例子很简单(但会自然地变得乱七八糟)。

  1. namespace rosettacode  
  2. {  
  3.   template<typename T> class queue  
  4.   {  
  5.   public:  
  6.     queue();  
  7.     ~queue();  
  8.     void push(T const& t);  
  9.     T pop();  
  10.     bool empty();  
  11.   private:  
  12.     void drop();  
  13.     struct node;  
  14.     node* head;  
  15.     node* tail;  
  16.   };  
  17.   
  18.   template<typename T> struct queue<T>::node  
  19.   {  
  20.     T data;  
  21.     node* next;  
  22.     node(T const& t): data(t), next(0) {}  
  23.   };  
  24.   
  25.   template<typename T>  
  26.    queue<T>::queue():  
  27.     head(0)  
  28.   {  
  29.   }  
  30.   
  31.   template<typename T>  
  32.    inline void queue<T>::drop()  
  33.   {  
  34.     node* n = head;  
  35.     head = head->next;  
  36.     delete n;  
  37.   }  
  38.   
  39.   template<typename T>  
  40.    queue<T>::~queue()  
  41.   {  
  42.     while (!empty())  
  43.       drop();  
  44.   }  
  45.   
  46.   template<typename T>  
  47.    void queue<T>::push(T const& t)  
  48.   {  
  49.     node*& next = head? tail->next : head;  
  50.     next = new node(t);  
  51.     tail = next;  
  52.   }  
  53.   
  54.   template<typename T>  
  55.    T queue<T>::pop()  
  56.   {  
  57.     T tmp = head->data;  
  58.     drop();  
  59.     return tmp;  
  60.   }  
  61.   
  62.   template<typename T>  
  63.    bool queue<T>::empty()  
  64.   {  
  65.     return head == 0;  
  66.   }  
  67. }  
namespace rosettacode
{
  template<typename T> class queue
  {
  public:
    queue();
    ~queue();
    void push(T const& t);
    T pop();
    bool empty();
  private:
    void drop();
    struct node;
    node* head;
    node* tail;
  };

  template<typename T> struct queue<T>::node
  {
    T data;
    node* next;
    node(T const& t): data(t), next(0) {}
  };

  template<typename T>
   queue<T>::queue():
    head(0)
  {
  }

  template<typename T>
   inline void queue<T>::drop()
  {
    node* n = head;
    head = head->next;
    delete n;
  }

  template<typename T>
   queue<T>::~queue()
  {
    while (!empty())
      drop();
  }

  template<typename T>
   void queue<T>::push(T const& t)
  {
    node*& next = head? tail->next : head;
    next = new node(t);
    tail = next;
  }

  template<typename T>
   T queue<T>::pop()
  {
    T tmp = head->data;
    drop();
    return tmp;
  }

  template<typename T>
   bool queue<T>::empty()
  {
    return head == 0;
  }
}


C#

    企业语言,为实现在大型机构中的可替换性而着力降低程序员的创造性。面向对象,静态类,冗赘,有大量的库和boilerplate模板,一切都暗示着它身上微软的血统。别误会,这个语言并不差。它只是不诱人,而这正是微软的目标。起码,它与Visual Basic相比有了长足的进步。我在以下情况使用:
  • Windows下开发
  • 游戏开发(好吧,主要是迫于微软,我还是更喜欢老伙计C或者C++)
  • 这个语言里出了轰动性事物:Unity3D, Xamarin, .NET, XNA。
代码示例

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.IO;  
  4. using System.Linq;  
  5.   
  6. class Program  
  7. {  
  8.     static SortedDictionary<TItem, int> GetFrequencies<TItem>(IEnumerable<TItem> items)  
  9.     {  
  10.         var dictionary = new SortedDictionary<TItem, int>();  
  11.         foreach (var item in items)  
  12.         {  
  13.             if (dictionary.ContainsKey(item))  
  14.             {  
  15.                 dictionary[item]++;  
  16.             }  
  17.             else  
  18.             {  
  19.                 dictionary[item] = 1;  
  20.             }  
  21.         }  
  22.         return dictionary;  
  23.     }  
  24.   
  25.     static void Main(string[] arguments)  
  26.     {  
  27.         var file = arguments.FirstOrDefault();  
  28.         if (File.Exists(file))  
  29.         {  
  30.             var text = File.ReadAllText(file);  
  31.             foreach (var entry in GetFrequencies(text))  
  32.             {  
  33.                 Console.WriteLine("{0}: {1}", entry.Key, entry.Value);  
  34.             }  
  35.         }  
  36.     }  
  37. }  
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

class Program
{
    static SortedDictionary<TItem, int> GetFrequencies<TItem>(IEnumerable<TItem> items)
    {
        var dictionary = new SortedDictionary<TItem, int>();
        foreach (var item in items)
        {
            if (dictionary.ContainsKey(item))
            {
                dictionary[item]++;
            }
            else
            {
                dictionary[item] = 1;
            }
        }
        return dictionary;
    }

    static void Main(string[] arguments)
    {
        var file = arguments.FirstOrDefault();
        if (File.Exists(file))
        {
            var text = File.ReadAllText(file);
            foreach (var entry in GetFrequencies(text))
            {
                Console.WriteLine("{0}: {1}", entry.Key, entry.Value);
            }
        }
    }
}
是不是很像Java?


Objective-C

比起C++(和C#),我对Objective-C印象好得多。它的语法不漂亮,但是作为语言我喜欢它。它有一套很好的基于NextStep的库,它是C语言的真正的升华,而且没有扩展到失控、使关键字与其父语言产生歧义。正如我说的,它的代码不太美观并且不容易读懂,尤其是嵌套函数时,但它的美妙在于概念和方法,而不在语法。看这个嵌套调用:
  1. char bytes[] = "some data";  
  2. NSString *string = [[NSString alloc] initWithBytes:bytes length:9 encoding:NSASCIIStringEncoding];  
char bytes[] = "some data";
NSString *string = [[NSString alloc] initWithBytes:bytes length:9 encoding:NSASCIIStringEncoding];


对于C语言的后代来说,这是段美妙的代码,用到了Objective-C中所谓的代码块。

  1. #import <Foundation/Foundation.h>  
  2.   
  3. typedef NSArray *(^SOfN)(id);  
  4.   
  5. SOfN s_of_n_creator(int n) {  
  6.   NSMutableArray *sample = [[NSMutableArray alloc] initWithCapacity:n];  
  7.   __block int i = 0;  
  8.   return ^(id item) {  
  9.     i++;  
  10.     if (i <= n) {  
  11.       [sample addObject:item];  
  12.     } else if (rand() % i < n) {  
  13.       sample[rand() % n] = item;  
  14.     }  
  15.     return sample;  
  16.   };  
  17. }  
  18.   
  19. int main(int argc, const charchar *argv[]) {  
  20.   @autoreleasepool {  
  21.   
  22.     NSCountedSet *bin = [[NSCountedSet alloc] init];  
  23.     for (int trial = 0; trial < 100000; trial++) {  
  24.       SOfN s_of_n = s_of_n_creator(3);  
  25.       NSArray *sample;  
  26.       for (int i = 0; i < 10; i++) {  
  27.         sample = s_of_n(@(i));  
  28.       }  
  29.       [bin addObjectsFromArray:sample];  
  30.     }  
  31.     NSLog(@"%@", bin);  
  32.   
  33.   }  
  34.   return 0;  
  35. }  
#import <Foundation/Foundation.h>

typedef NSArray *(^SOfN)(id);

SOfN s_of_n_creator(int n) {
  NSMutableArray *sample = [[NSMutableArray alloc] initWithCapacity:n];
  __block int i = 0;
  return ^(id item) {
    i++;
    if (i <= n) {
      [sample addObject:item];
    } else if (rand() % i < n) {
      sample[rand() % n] = item;
    }
    return sample;
  };
}

int main(int argc, const char *argv[]) {
  @autoreleasepool {

    NSCountedSet *bin = [[NSCountedSet alloc] init];
    for (int trial = 0; trial < 100000; trial++) {
      SOfN s_of_n = s_of_n_creator(3);
      NSArray *sample;
      for (int i = 0; i < 10; i++) {
        sample = s_of_n(@(i));
      }
      [bin addObjectsFromArray:sample];
    }
    NSLog(@"%@", bin);

  }
  return 0;
}

Clojure

    作为 Scheme程序员,我对Clojure怀有敬意:这是人们所说的现代Lisp,有着独到的特性。我认为Clojure的长处是与Java之间的互操作性和核心语言中的并发功能。它与Scala如同手足,但各有特点:一个是Lisp,一个是面向对象和函数式语言的混合体,Clojure因为括号过多而较为冷门。选择这两种语言中的哪一个进行编程取决于个人风格,因为两者都没有长期而成功的应用程序产出为其提供支撑,这点上它们不及同样基于JVM的Java和PHP。对于任何基于JVM的语言,另一件需要考虑的事情是虚拟机的启动时间,它们处理起小任务来略显笨重。我会在以下情况用Clojure:
  • 网络编程。网络编程有许多好选择,Clojure族群在这个领域看起来十分活跃。
  • 想绕过Java那一套来使用JVM时。这能让程序员既开心又高效。 
  • 探索性的编程,发展成产品代码的探索。这实际上是Lisp的强项,但Clojure基于Java,有许多开源代码资源。
  • 安卓程序开发?安卓程序开发的图形用户借口模式很大程度是基于类继承(这意味着你能将它作为一个插件库使用,而必须遵循某些结构)。这可以实现,但是不像直接用Java继承那样自然。
经典的Clojure代码:

  1. (defn divides? [k n] (= (rem n k) 0))  
  2.   
  3. (defn prime? [n]  
  4.   (if (< n 2)  
  5.     false  
  6.     (empty? (filter #(divides? % n) (take-while #(<= (* % %) n) (range 2 n))))))  
(defn divides? [k n] (= (rem n k) 0))

(defn prime? [n]
  (if (< n 2)
    false
    (empty? (filter #(divides? % n) (take-while #(<= (* % %) n) (range 2 n))))))

Lisp式的简单队列定义,

  1. (defn make-queue []  
  2.   (atom []))  
  3.   
  4. (defn enqueue [q x]  
  5.   (swap! q conj x))  
  6.   
  7. (defn dequeue [q]  
  8.   (if (seq @q)  
  9.     (let [x (first @q)]  
  10.       (swap! q subvec 1)  
  11.       x)  
  12.     (throw (IllegalStateException. "Can't pop an empty queue."))))  
  13.   
  14. (defn queue-empty? [q]  
  15.   (empty? @q))  
(defn make-queue []
  (atom []))

(defn enqueue [q x]
  (swap! q conj x))

(defn dequeue [q]
  (if (seq @q)
    (let [x (first @q)]
      (swap! q subvec 1)
      x)
    (throw (IllegalStateException. "Can't pop an empty queue."))))

(defn queue-empty? [q]
  (empty? @q))

D

我以前喜欢D,D就像是完善版的C++。D1像面向底层的Python,比如Python和C的合体之类的。它棒极了:你能感觉到开发起来多迅速,它专注于算法而不是语言,但并不牺牲底层控制,以备不时之需。D2带有许多C++的复杂性,还带着Andrei Alexandrescu的创新意味。一部分人对此不满意,尽管D2对并发性更加重视。D2不再是一种简洁的语言,但因为有许多未测试的功能,它感觉更像个实验性的语言。我还是喜欢它的,但我认为在C++的高使用率面前,它的功能相形见绌(一旦复杂起来)。另外我认为Go正在吞并D本应获得的市场。就算把D做得更快、功能更酷,Walter和Andrei也没法与Google竞争。你可能正如我一样喜欢D,但它前景并不明朗。还是继续用C++,或者试试Go吧,它的本地并发支持更强大。那么,我会在什么时候用D语言呢?
  • 从零开始开发一个与C有接口或者是与C++有联系的项目时。不过,你得提前设想好接口。举个例子,如果需要使用C++的GUI库,我不建议使用D。因为这通常以为着要从内部处理C++的继承,那么所有优势都会被抵消。如果需要C++的插件库,就这么做吧:创建对象,使用其函数,但不用模板或是C++的继承。
  • 进行底层编程并且需要快速二进制功能时。还是那样,做自己的事情,就像一个独立程序。
  • 希望语言能更好地在本地支持并发性时。
我们来看一些带有纯函数和不可变声明的D2的惯用法。
  1. uint grayEncode(in uint n) pure nothrow {  
  2.     return n ^ (n >> 1);  
  3. }  
  4.   
  5. uint grayDecode(uint n) pure nothrow {  
  6.     auto p = n;  
  7.     while (n >>= 1)  
  8.         p ^= n;  
  9.     return p;  
  10. }  
  11.   
  12. void main() {  
  13.     import std.stdio;  
  14.   
  15.     " N     N2      enc     dec2 dec".writeln;  
  16.     foreach (immutable n; 0 .. 32) {  
  17.         immutable g = n.grayEncode;  
  18.         immutable d = g.grayDecode;  
  19.         writefln("%2d: %5b => %5b => %5b: %2d", n, n, g, d, d);  
  20.         assert(d == n);  
  21.     }  
  22. }  
uint grayEncode(in uint n) pure nothrow {
    return n ^ (n >> 1);
}

uint grayDecode(uint n) pure nothrow {
    auto p = n;
    while (n >>= 1)
        p ^= n;
    return p;
}

void main() {
    import std.stdio;

    " N     N2      enc     dec2 dec".writeln;
    foreach (immutable n; 0 .. 32) {
        immutable g = n.grayEncode;
        immutable d = g.grayDecode;
        writefln("%2d: %5b => %5b => %5b: %2d", n, n, g, d, d);
        assert(d == n);
    }
}
表的最大元素:

  1. [9, 4, 3, 8, 5].reduce!max.writeln;  
[9, 4, 3, 8, 5].reduce!max.writeln;
它绝对比C++更简洁,更具表达力,差距不是一点点。


Erlang

    这是一个目的明确的语言。 Erlang的网页说得很清楚:(……)构建可扩展性强、可用性高的软实时系统。客户遍及电信、银行、电子商务、计算机电话和即时消息等行业。Erlang的运行时系统固有对并发、分布和容错的支持。Erlang经实践证明可靠,而且产出过一些高难度应用程序,例如WhatsApp.
代码本身给人功能强大之感,其语法简洁易读。
看一个简单的并发程序代码:
  1. -module(hw).  
  2. -export([start/0]).  
  3.   
  4. start() ->  
  5.    [ spawn(fun() ->  say(self(), X) end) || X <- ['Enjoy', 'Rosetta', 'Code'] ],  
  6.    wait(2),  
  7.    ok.  
  8.   
  9. say(Pid,Str) ->  
  10.    io:fwrite("~s~n",[Str]),  
  11.    Pid ! done.  
  12.   
  13. wait(N) ->  
  14.    receive  
  15.        done -> case N of  
  16.            0 -> 0;  
  17.            _N -> wait(N-1)  
  18.        end  
  19.    end.  
-module(hw).
-export([start/0]).

start() ->
   [ spawn(fun() ->  say(self(), X) end) || X <- ['Enjoy', 'Rosetta', 'Code'] ],
   wait(2),
   ok.

say(Pid,Str) ->
   io:fwrite("~s~n",[Str]),
   Pid ! done.

wait(N) ->
   receive
       done -> case N of
           0 -> 0;
           _N -> wait(N-1)
       end
   end.

Go

我还没有亲自用过它。但很显然,Google的这一尝试,目的在于创造一种基于C语言、带有C++优点、并发支持比两者都强的语言。它有优于C++的功能,而且简单得多。它没有不安全指针运算,拥有闭包、第一级函数和垃圾回收机制。Go可能是服务器语言的未来。所以,我什么时候会尝试Go呢?
  • 编写对性能和可靠性要求非常高的服务器应用程序,包括网络应用程序。
  • 编写需要底层控制的高并发代码(不然我更喜欢Erlang)。
Go的并发代码
  1. package main  
  2.   
  3. import (  
  4.     "fmt"  
  5.     "math/rand"  
  6.     "time"  
  7. )  
  8.   
  9. func main() {  
  10.     words := []string{"Enjoy", "Rosetta", "Code"}  
  11.     rand.Seed(time.Now().UnixNano())  
  12.     q := make(chan string)  
  13.     for _, w := range words {  
  14.         go func(w string) {  
  15.             time.Sleep(time.Duration(rand.Int63n(1e9)))  
  16.             q <- w  
  17.         }(w)  
  18.     }  
  19.     for i := 0; i < len(words); i++ {  
  20.         fmt.Println(<-q)  
  21.     }  
  22. }  
package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    words := []string{"Enjoy", "Rosetta", "Code"}
    rand.Seed(time.Now().UnixNano())
    q := make(chan string)
    for _, w := range words {
        go func(w string) {
            time.Sleep(time.Duration(rand.Int63n(1e9)))
            q <- w
        }(w)
    }
    for i := 0; i < len(words); i++ {
        fmt.Println(<-q)
    }
}

Haskell

    比起这个列表上的其他语言,这种语言像是一种更高级的思考工具。它有一系列无所不能的程序库,还有一群死忠拥护者。可以说这是一种高门槛的语言。我认为,使用它能开拓思路,还能让你接触到编程界最聪明的人。
    就算不用来写真正的程序,我认为Haskell也很值得学。虽然它是一种相对模糊的语言,但我把它定位为“适用”,因为它在 某些方面有实际用处,金融业首当其冲。
Haskell的代码往往非常紧凑,表达力强,尽管有点抽象(因为很多函数是概念上的操作,而不是过程中的一步)。我个人不喜欢它的语法(我认为太多了),但至少它服务于一个目的,不混乱(说你呢Perl!)。这种语言漂亮而连贯,自己看吧:

  1. binarySearch :: Integral a => (a -> Ordering) -> (a, a) -> Maybe a  
  2. binarySearch p (low,high)  
  3.   | high < low = Nothing  
  4.   | otherwise =  
  5.       let mid = (low + high) `div` 2 in  
  6.       case p mid of  
  7.         LT -> binarySearch p (low, mid-1)  
  8.         GT -> binarySearch p (mid+1, high)  
  9.         EQ -> Just mid  

Java

    和C#一样,但有JVM。它面世最早(实际上C#模仿了它),算是面向对象语言界的“标准”。从网络应用到游戏,它无处不在,只缺席嵌入式设备和高性能并行计算软件。它(尤其是它的虚拟机)为许多其他语言提供了基础。Processing可以作为一个有趣的例子,它是一个皮囊语言(只是披上马甲的Java),被应用于教育和数码艺术。我什么时候推荐用Java:

  • 多数情况:如果你希望获取大量人力和知识储备,即,你想要别人维护你的软件。
  • 如果你需要通用于尽可能多的设备的多平台虚拟机。

Java7的读取文件的代码例子:

  1. import java.util.List;  
  2. import java.nio.charset.Charset;  
  3. import java.nio.file.*;  
  4.   
  5. public class ReadAll {  
  6.     public static List<String> readAllLines(String filesname){  
  7.         Path file = Paths.get(filename);  
  8.         return Files.readAllLines(file, Charset.defaultCharset());  
  9.     }  
  10.   
  11.    public static byte[] readAllBytes(String filename){  
  12.        Path file = Paths.get(filename);  
  13.        return Files.readAllBytes(file);  
  14.    }  
  15. }  
import java.util.List;
import java.nio.charset.Charset;
import java.nio.file.*;

public class ReadAll {
    public static List<String> readAllLines(String filesname){
        Path file = Paths.get(filename);
        return Files.readAllLines(file, Charset.defaultCharset());
    }

   public static byte[] readAllBytes(String filename){
       Path file = Paths.get(filename);
       return Files.readAllBytes(file);
   }
}


你大概已经见过很多Java代码,所以我就用类定义来烦你了。

Javascript

    2010年代的通用语,网络的语言。有趣的是,它以前被认为缺点多多、十分局限,但现在大量的程序员已经证明,只要遵循规范,使用技巧,Javascript也可以很优秀。尤其是它的大量的库和实现,弥补了Javascript的设计缺陷和功能缺失(比如模块系统)。拜它们所赐,现在甚至有了针对服务器的Javascript,它美妙的对称性终于穿过前端,来到了后端。
    人们投入大量精力研究如何改善Javascript性能及其它可以编译为Javascript的衍生语言。这证明了用户群是一种语言所能拥有的最强大的资本之一(甚至可以说是唯一)。有趣的是,无数的库反复在做同样的事情,使得库开发者在这一领域的竞争空前激烈。看Grunt和Gulp的例子,或者一大波互相竞争的Javascript衍生物(Coffeescript,Typescript,Livescript等等)。太疯狂了。
下面的代码展示了Javascript基于原型的类和继承:

[javascript] view plain copy print ?
  1. function Car(brand, weight) {  
  2.   this.brand = brand;  
  3.   this.weight = weight || 1000;  
  4. }  
  5. Car.prototype.getPrice = function() {  
  6.   return this.price;  
  7. }  
  8.   
  9. function Truck(brand, size) {  
  10.   this.constructor(brand, 2000);  
  11.   this.size = size;  
  12. }  
  13. Truck.prototype = new Car;  
  14.   
  15. var cars = [  
  16.   new Car("Mazda"),  
  17.   new Truck("Volvo", 2)  
  18. ];  
  19.   
  20. for (var i=0; i<cars.length; i++) {  
  21.     console.log(cars[i]);  
  22.     console.log("brand: "+cars[i].brand+". weight: "+cars[i].weight+"." + (( cars[i].hasOwnProperty('size') ) ? " size: "+cars[i].size : ""));  
  23.     console.log("Car: %s. Truck: %s\n", cars[i] instanceof Car, cars[i] instanceof Truck);  
  24. }  
function Car(brand, weight) {
  this.brand = brand;
  this.weight = weight || 1000;
}
Car.prototype.getPrice = function() {
  return this.price;
}

function Truck(brand, size) {
  this.constructor(brand, 2000);
  this.size = size;
}
Truck.prototype = new Car;

var cars = [
  new Car("Mazda"),
  new Truck("Volvo", 2)
];

for (var i=0; i<cars.length; i++) {
    console.log(cars[i]);
    console.log("brand: "+cars[i].brand+". weight: "+cars[i].weight+"." + (( cars[i].hasOwnProperty('size') ) ? " size: "+cars[i].size : ""));
    console.log("Car: %s. Truck: %s\n", cars[i] instanceof Car, cars[i] instanceof Truck);
}

使用Lo-dash库的类似函数式的代码:

[javascript] view plain copy print ?
  1. var characters = [  
  2.   { 'name''barney',  'age': 36 },  
  3.   { 'name''fred',    'age': 40 },  
  4.   { 'name''pebbles''age': 1 }  
  5. ];  
  6.   
  7. var youngest = _.chain(characters)  
  8.     .sortBy('age')  
  9.     .map(function(chr) { return chr.name + ' is ' + chr.age; })  
  10.     .first()  
  11.     .value();  
var characters = [
  { 'name': 'barney',  'age': 36 },
  { 'name': 'fred',    'age': 40 },
  { 'name': 'pebbles', 'age': 1 }
];

var youngest = _.chain(characters)
    .sortBy('age')
    .map(function(chr) { return chr.name + ' is ' + chr.age; })
    .first()
    .value();


我觉得把两种风格混合起来很酷,只要你掌握了Javascript的特性(是的,比如this的用法)。

OCaml

它有点像Haskell,但更能满足程序员的想法。在必要的时候,为了更容易的解决方案牺牲了一些语言的纯洁性,比如过程式或者面向对象的方法最为有效的情况。有些公司使用OCaml,我想就是为了它相较于Haskell的这个优点。看看下面的片段:

  1. let n_arrays_iter ~f = function  
  2.   | [] -> ()  
  3.   | x::xs as al ->  
  4.       let len = Array.length x in  
  5.       let b = List.for_all (fun a -> Array.length a = len) xs in  
  6.       if not b then invalid_arg "n_arrays_iter: arrays of different length";  
  7.       for i = 0 to pred len do  
  8.         let ai = List.map (fun a -> a.(i)) al in  
  9.         f ai  
  10.       done  
let n_arrays_iter ~f = function
  | [] -> ()
  | x::xs as al ->
      let len = Array.length x in
      let b = List.for_all (fun a -> Array.length a = len) xs in
      if not b then invalid_arg "n_arrays_iter: arrays of different length";
      for i = 0 to pred len do
        let ai = List.map (fun a -> a.(i)) al in
        f ai
      done

看起来很像Haskell,对不对?但那个for循环有如此有命令式特色……

PHP

    不要先入为主地认为PHP很可怕。向斯巴达人学习,享受PHP的折磨吧。有个好消息:如果你享受用PHP编程,那你就是真正的程序员了。这也是自由职业者常用的语言。什么情况下用PHP?

  • 如果你想要世界上最大的网络程序员资源库。
  • 如此而已,没有别的理由了。

漂亮的PHP代码,希望你喜欢美元。

  1. function hashJoin($table1$index1$table2$index2) {  
  2.     foreach ($table1 as $s)  
  3.         $h[$s[$index1]][] = $s;  
  4.     foreach ($table2 as $r)  
  5.       foreach ($h[$r[$index2]] as $s)  
  6.         $result[] = array($s$r);  
  7.     return $result;  
  8. }  
  9.   
  10. $table1 = array(array(27, "Jonah"),  
  11.            array(18, "Popeye"),  
  12.            array(28, "Alan"));  
  13. $table2 = array(array("Jonah""Whales"),  
  14.            array("Jonah""Spiders"),  
  15.            array("Alan""Ghosts"),  
  16.            array("Bob""foo"));  
  17.   
  18. foreach (hashJoin($table1, 1, $table2, 0) as $row)  
  19.     print_r($row);  
function hashJoin($table1, $index1, $table2, $index2) {
    foreach ($table1 as $s)
        $h[$s[$index1]][] = $s;
    foreach ($table2 as $r)
      foreach ($h[$r[$index2]] as $s)
        $result[] = array($s, $r);
    return $result;
}

$table1 = array(array(27, "Jonah"),
           array(18, "Popeye"),
           array(28, "Alan"));
$table2 = array(array("Jonah", "Whales"),
           array("Jonah", "Spiders"),
           array("Alan", "Ghosts"),
           array("Bob", "foo"));

foreach (hashJoin($table1, 1, $table2, 0) as $row)
    print_r($row);


Python

    这是种美观的语言。我喜欢它的基于空格的块结构,没必要老是用难看的分号。我如此喜欢它,以至于打算这样写Javascript。但这事取决于口味,实际上很多人正好因此不喜欢这种语言。这是种简洁的语言,能减轻用户语法上的负担。尽管其效果有争议,这种语言依然有庞大的拥护者群,和它的同伴Ruby相比,优势明显。这两种语言之间很难抉择,不过Python似乎传播更广,对于很多应用领域也更加适用。我什么时候用Python?

  • 网络开发
  • 科学计算和数据分析
  • 系统管理和工具
  • 游戏或3D应用程序脚本
  • 跨平台支持

不错的Python代码:

  1. from itertools import islice  
  2.   
  3. def hamming2():  
  4.     '''''\ 
  5.     A text documenting this function (stripped) 
  6.     '''  
  7.     h = 1  
  8.     _h=[h]    # memoized  
  9.     multipliers  = (235)  
  10.     multindeces  = [0 for i in multipliers] # index into _h for multipliers  
  11.     multvalues   = [x * _h[i] for x,i in zip(multipliers, multindeces)]  
  12.     yield h  
  13.     while True:  
  14.         h = min(multvalues)  
  15.         _h.append(h)  
  16.         for (n,(v,x,i)) in enumerate(zip(multvalues, multipliers, multindeces)):  
  17.             if v == h:  
  18.                 i += 1  
  19.                 multindeces[n] = i  
  20.                 multvalues[n]  = x * _h[i]  
  21.         # cap the memoization  
  22.         mini = min(multindeces)  
  23.         if mini >= 1000:  
  24.             del _h[:mini]  
  25.             multindeces = [i - mini for i in multindeces]  
  26.         #  
  27.         yield h  
from itertools import islice

def hamming2():
    '''\
    A text documenting this function (stripped)
    '''
    h = 1
    _h=[h]    # memoized
    multipliers  = (2, 3, 5)
    multindeces  = [0 for i in multipliers] # index into _h for multipliers
    multvalues   = [x * _h[i] for x,i in zip(multipliers, multindeces)]
    yield h
    while True:
        h = min(multvalues)
        _h.append(h)
        for (n,(v,x,i)) in enumerate(zip(multvalues, multipliers, multindeces)):
            if v == h:
                i += 1
                multindeces[n] = i
                multvalues[n]  = x * _h[i]
        # cap the memoization
        mini = min(multindeces)
        if mini >= 1000:
            del _h[:mini]
            multindeces = [i - mini for i in multindeces]
        #
        yield h


Ruby

    Rails框架下的Ruby。这是它能登上这个列表的唯一原因。当然,现在其他框架下的Ruby很常见,但一切都从Rails开始。在那以前,Ruby只是日本来的晦涩编程语言。厉害的应用或者框架能催生庞大用户群,用户群能反过来产出更多厉害的应用或者框架,使本来会失去立足之地的语言变得流行,Ruby就是一个最好的例子。
    我听很多用Ruby的程序员说过,自己也有体会,Ruby的乐趣在于用。换句话说,它与那种让人丧气的语言正相反,不过我不确定这来自于语言本身还是Rails。metasploit的工作人员似乎一开始就十分明确这一点。
这是刚才的Python算法用Ruby写的结果。方法不同,也显示了Ruby更为函数式的风格倾向。

  1. hamming = Enumerator.new do |yielder|  
  2.   next_ham = 1  
  3.   queues = { 2 => [], 3 => [], 5 => [] }  
  4.   
  5.   loop do  
  6.     yielder << next_ham   # or: yielder.yield(next_ham)  
  7.   
  8.     [2,3,5].each {|m| queues[m]<< (next_ham * m)}  
  9.     next_ham = [2,3,5].collect {|m| queues[m][0]}.min  
  10.     [2,3,5].each {|m| queues[m].shift if queues[m][0]== next_ham}  
  11.   end  
  12. end  
  13.   
  14. idx = 1  
  15. hamming.each do |ham|  
  16.   case idx  
  17.   when (1..20), 1691  
  18.     p [idx, ham]  
  19.   when 1_000_000  
  20.     p [idx, ham]  
  21.     break  
  22.   end  
  23.   idx += 1  
  24. end  
hamming = Enumerator.new do |yielder|
  next_ham = 1
  queues = { 2 => [], 3 => [], 5 => [] }

  loop do
    yielder << next_ham   # or: yielder.yield(next_ham)

    [2,3,5].each {|m| queues[m]<< (next_ham * m)}
    next_ham = [2,3,5].collect {|m| queues[m][0]}.min
    [2,3,5].each {|m| queues[m].shift if queues[m][0]== next_ham}
  end
end

idx = 1
hamming.each do |ham|
  case idx
  when (1..20), 1691
    p [idx, ham]
  when 1_000_000
    p [idx, ham]
    break
  end
  idx += 1
end


Scala

似乎在所有基于JVM的语言中一枝独秀。我确信,和主要竞争者之一Clojure相比,Scala大部分的优势来自于熟悉的语法。和Clojure一样,这种语言进入这个名单是因为能和Java轻松地结合,因此适用于实际项目。下面这个小片段生成了Hofstadter Q序列:

  1. object HofstadterQseq extends App {  
  2.   val Q: Int => Int = n => {  
  3.     if (n <= 2) 1  
  4.     else Q(n-Q(n-1))+Q(n-Q(n-2))  
  5.   }  
  6.   (1 to 10).map(i=>(i,Q(i))).foreach(t=>println("Q("+t._1+") = "+t._2))  
  7.   println("Q("+1000+") = "+Q(1000))  
  8. }  
object HofstadterQseq extends App {
  val Q: Int => Int = n => {
    if (n <= 2) 1
    else Q(n-Q(n-1))+Q(n-Q(n-2))
  }
  (1 to 10).map(i=>(i,Q(i))).foreach(t=>println("Q("+t._1+") = "+t._2))
  println("Q("+1000+") = "+Q(1000))
}


Scheme

这种语言进入这个名单很可能有争议,但我有自己的理由。这个语言主要有三个问题:
    1.缺乏一种真正好的实现方法,以及若干稍逊色的竞争者
    2.库太少
    3.性能不佳
    第一点并不完全正确:实现方法太多了,但好的实现方法数量有限,你得选择最适合的那种。第二点也不完全对:库是有的,但太分散。有许多大大小小的项目可提供替代品。查看支持代码时这种语言的分散性凸显:你得用自己的方法实现。不过,这通常并不难,耗时也不多,更重要的是,只要使用有良好FFI支持的Scheme实现方法(比如Gambit和Chicken Scheme),就能轻松获取C语言的所有库。我真的会这么做,而且和你可能想象的不同,效果很好。最后,糟糕的性能。这一条完全错误。Gambit之类的实现速度很快,还有许多优化选择(包括算法优化,全局Scheme编译器声明,当然还有,有需要时轻易就能把C和Scheme结合)。
    是的,我是Scheme是狂热爱好者,但是,我承认它有一个致命的弱点:它的共享度很烂,因为用户群不怎么样。它如此灵活,面对一个任务,每个程序员都想得出自己的完美解决方案。这点和Java完全相反:Scheme很适合个人或者小团队项目,进行原型开发和探索性编程,在大型团队中的作用未经证明。但在适用情况下非常好,开发体验极为快捷、愉悦。最后,这种语言还有一个非常有意思的特点:使用Scheme-to-Js编译器很容易编译为Javascript,让你享受到和用Node.js在服务器上开发一样的对称性。以下是我选择Scheme的几种情况举例:

  • 没有确切目标的探索性编程
  • 为一个目标快速进行原型开发且不需要大型库(Python和Ruby中才有的那种)
  • 为C或C++的大型程序或者平台写脚本时
  • 编写需要大部分从头写起的应用程序时
  • 做游戏或者基于OpenGl/ES的多平台应用程序

下面是三个Scheme代码示例。这些函数需要自己来实现,因为在所有实现里没有现成的,不过它们依然常见而有效。适用于所有实现里(前提是兼容R5RS)。

  1. ;;! Recursive map that applies function to each node  
  2. (define (map** f l)  
  3.   (cond  
  4.    ((null? l) '())  
  5.    ((not (pair? l)) (f l))  
  6.    (else  
  7.     (cons (f (map** f (car l))) (f (map** f (cdr l)))))))  
  8.   
  9. ;;! Explicit currying of an arbitrary function  
  10. (define (curry fun arg1 . args)  
  11.   (if (pair? args)  
  12.       (let ((all-args (cons arg1 args)))  
  13.         (lambda x  
  14.           (apply fun (append all-args x))))  
  15.       (lambda x  
  16.         (apply fun (cons arg1 x)))))  
  17.   
  18. ;;! Implementation of filter, with the match macro  
  19. (define (filter p lst)  
  20.   (match lst  
  21.    ('() '())  
  22.    (((? p) . tl) (cons (car lst) (filter/match p tl)))  
  23.    ((hd . tl) (filter/match p tl))))  
;;! Recursive map that applies function to each node
(define (map** f l)
  (cond
   ((null? l) '())
   ((not (pair? l)) (f l))
   (else
    (cons (f (map** f (car l))) (f (map** f (cdr l)))))))

;;! Explicit currying of an arbitrary function
(define (curry fun arg1 . args)
  (if (pair? args)
      (let ((all-args (cons arg1 args)))
        (lambda x
          (apply fun (append all-args x))))
      (lambda x
        (apply fun (cons arg1 x)))))

;;! Implementation of filter, with the match macro
(define (filter p lst)
  (match lst
   ('() '())
   (((? p) . tl) (cons (car lst) (filter/match p tl)))
   ((hd . tl) (filter/match p tl))))

再看看其他有趣的例子吧。
    不管是自力更生还是借助Scheme Spheres等工具,如果你解决了极小型开发框架的问题,你就了不得啦。

恐龙级语言

    这种语言无所谓好坏。它们似乎被遗忘了,远离话题的中心,也没有什么理由吸引我们去使用。不过也许我们错了!

Assembly

  现在没有人真的用Assembly编程了,连优化都用不到,因为编译器可以做得更好。没错,总有人比编译器更厉害,但我想那样的人必须非常非常聪明,而且知识渊博。
    但是,有一个重要的理由使你必须使用它:终极编程体验。使用SICP和各种Lisp语言能让人茅塞顿开,但我相信,最无以伦比的醒悟来自于真正理解所有这些语言的归宿:仅仅是一串处理器指令,不管是声明式语言,还是逻辑式、函数式、面向对象语言,都抽离于它们的高层体系结构之外。Assembly属于伟大语言之列。什么时候使用?

  •  学习时
  •  需要用到Assembly的系统开发
  •  对某个体系结构非常熟悉,并且需要手写其中一部分代码时


Common Lisp

    我用过Autolisp给AutoCAD做优化,但要是在Lisp、Scheme、Clojure中做选择,我选择Scheme。对我来说,它在三种还不错的Lisp语言中排名第三。它感觉有些臃肿,缺少Lisp的精髓:美感,优雅和简约。我会用它做快速原型开发,比起Scheme,它的优点是拥有现成的库,但Scheme会在这方面迎头赶上。另外,原型开发方面,还有更好的、同样拥有库的语言。

Perl

    有人写过美妙的歌曲来赞美Perl。显然是一个具有宗教性质的语言,它拥有自己的僧侣和预言家。它的创造者是语言学家Larry Wall,可以看得出他的特质投射到了这一语言中。它真的很让我着迷,就像编程语言里的拉丁语。同志们,行业里的高人依然在谈论Perl,一定有其道理。Larry的一句箴言说出了Perl的精髓:“真正的程序员能用任何语言写出汇编语言”。
    总的来说,Perl的语言学概念可以说令我赞叹。但它的语法有些怪异,用得不对就可能产生很糟糕的结果(和Lisp的宏十分类似)。我认为这种语言十分适合解决小问题,非常方便:它有很全面的库(CPAN),几乎有求必应,使得解决问题无比的简单。使用Perl的最糟结果,是为了写系统脚本而掌握了一样宝贵的工具。PS:有人告诉我Perl的对象支持烂极了,但在我看来这是个优点(也许我偏激了),不过我也怀疑这个论断的真实性。
  看看这两个伟大的作品:POE(用于反应式系统、合作多任务处理和网络应用程序的框架)和Mojolicious,一个实时网络框架。
  BASIC, COBOL, Fortran, Pascal, Visual Basic…
  如果你需要使用这些语言中的任意一个,上帝都会保佑你的。他们应用在非常特定的领域(像Fortran,用于天文学和高性能计算,或者COBOL,用于银行等行业的庞大古老的系统),但它们几乎都受到程序员们的一致抨击。为什么要用它们?我给你一个很好的理由:维护别人代码就能赚到相当滋润的时薪。自己来写?想都别想:)

  Smalltalk

  第一个真正的面对对象语言,但在我看来它基本上已经被遗忘了。
  不可理喻的语言
  用于生产目的时也许不可理喻,但它们绝对能促使你成为更优秀的程序员(这完全合理)。到底什么有意义,选择权在你。我能说什么呢,我喜欢不可理喻的选择。

  Array, J

  这是我要学的语言,因为我听说它们有特色,能使人思维开阔,超越函数式和声明式语言的限制。

  Factor, Forth

  基于堆栈的语言是非常强大,值得学习。对扩展思维有益。已经加入我的目标列表。

  F#

  这是微软扮酷的尝试。语言不错,但是我们大多数人已经得到过惨痛的教训,要远离微软。公司赞助的语言已经够多了。

  Oz

  这是一种典型的多范式语言,带有约束和分布式编程功能。它拥有主流编程语言如函数式(即懒惰又有野心)、命令式和面向对象语言的大部分特点。

  Prolog/Datalog

  声明式逻辑语言总体上来说非常学术派。不过也有一些例外,可以在这个Stackoverflow提问里看到,Scheme也可以说是一个例子。

  Rust

  Mozilla在系统编程语言界的竞争者。它没有D一样的悠久历史,也不像Go一样有Google这种大公司支持。不过,我仍然希望看到Rust在未来成为系统开发的合理选择之一。
  Shen
  它进入这个名单,是因为我读到过Shen里有可更换皮肤的类型系统和其他新颖有趣的点子。然而,它的实现还处在试验阶段,语言的许可证让人无法接受。它的创造者似乎生活在另一个时代。

  TCL

  我用过几个月,那时我急需同像性的、绑定了我当时需要的库(BRL-CAD)的语言。我认为这种语言被低估了,但被低估的语言还有很多。而且它没有特酷的功能作为闪光点(像Erlang那样)。


  结论

  我以我选择的语言开始了这个漫长的帖子。编程是美妙的艺术,我全身心喜欢它,所以我承认个人经历给我造成了很强的偏向性。由于太多的不确定因素,选择编程语言有时很困难。以我的观点看,有三个因素首当其冲,顺序如下:

  1. 项目是否以产品生产为目标,是否属于一个拥有文化底蕴的大型组织,是否倾向于某一编程语言?
  2. 当前任务是否特殊到需要某一编程语言的特定功能?
  3. 你喜欢或者是想要尝试用这种语言编程吗?

  这是我处理这个问题的方法。尽管有时候会打破规则……

你有更能代表这些语言特点的代码片段吗?


本文经原作者许可翻译,未经许可禁止转载


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值