c语言 有趣简单编程_编程语言中的6个有趣功能

c语言 有趣简单编程

Java是我专业学习和使用的第一门语言。 大约十年半以来,这一直是我的生计。 但是,这并不是我一整年以来一直学习或使用的唯一语言:例如,很久以前,我不得不开发JavaScript代码来实现动态用户界面。 那时,它被称为DHTML ....几年前,我还自学了Kotlin,从未停止使用它。 去年,在一家新公司工作时,我尝试了Clojure-尽管效果不佳。

在所有情况下,Java仍然代表着我学习和判断其他语言的基础。 这是语言的一些有趣特征,我发现这些特征来自Java背景,颇具挑战性。

JavaScript:原型

JavaScript是我必须与Java一起使用的第一语言。 尽管JavaScript在过去的这些年里一直在发展,但其中一个共同的功能却非常奇怪地实现了:新对象的实例化。

在Java中,首先创建一个

publicclassPerson{

  privatefinalStringname;
  privatefinalLocalDatebirthdate;

  publicPerson(Stringname,LocalDatebirthdate){
    this.name=name;
    this.birthdate=birthdate;
  }

  publicStringgetName(){
    returnname;
  }

  publicLocalDategetBirthdate(){
    returnbirthdate;
  }
}

然后,可以继续创建该类的实例

varperson1=newPerson("John Doe",LocalDate.now());
varperson2=newPerson("Jane Doe",LocalDate.now());

JavaScript与Java语法非常相似:

classPerson{
  constructor(name,birthdate){
    this.name=name;
    this.birthdate=birthdate;
  }
}

letperson1=newPerson("John Doe",Date.now());
letperson2=newPerson("Jane Doe",Date.now());

平行线在那里停止。 得益于JavaScript动态的特性,可以向现有实例添加属性和函数。

person1.debug=function(){
  console.debug(this);
}

person1.debug();

但是,这些仅添加到实例。 其他实例缺少这些补充:

person2.debug();// Throws TypeError: person2.debug is not a function

为了向现在和将来的所有实例添加函数(或属性),需要利用原型的概念:

Person.prototype.debug=function(){
  console.debug(this);
}

person1.debug();
person2.debug();

letperson3=newPerson("Nicolas",Date.now());

person3.debug();

Kotlin:扩展功能/属性

几年前,我尝试自学Android。 我发现这种体验并不十分适合开发人员:当然,我了解目标之一是尽可能减小占用空间,但这是以非常简洁的API为代价的。

我记得必须调用带有很多参数的方法,其中大多数为null 。 我试图找到一种方法来解决这个问题...并发现Kotlin的扩展属性-具有默认参数。 我停止了学习Android的道路,但继续使用Kotlin。

我爱Kotlin。 许多人赞扬Kotlin的零安全方法。 我喜欢它,但对我来说,最高的价值在于其他地方。

假设我们经常需要大写字符串。 在Java中实现该目标的方法是使用静态方法创建一个类:

publicclassStringUtils{

  publicstaticStringcapitalize(Stringstring){
    varcharacter=string.substring(0,1).toUpperCase();
    varrest=string.substring(1,string.length()-1).toLowerCase();
    returncharacter+rest;
  }
}

在早期,没有一个项目没有StringUtilsDateUtils类。 幸运的是,现在,现有的库提供了最需要的功能, 例如 Apache Commons LangGuava 。 但是,它们遵循基于静态方法的相同设计原理。 令人遗憾的是,因为Java被认为是一种OOP语言。 不幸的是,静态方法不是面向对象的。

Kotlin允许在扩展函数和属性的帮助下向现有类分别添加行为。 语法非常简单,并且与面向对象的方法完全兼容:

funString.capitalize():String{
  valcharacter=substring(0,1).toUpperCase()
  valrest=substring(1,length-1).toLowerCase()
  returncharacter+rest
}

在编写Kotlin代码时,我经常使用它。

在幕后,Kotlin编译器生成的字节码类似于Java代码中的字节码。 它只是“唯一”的语法糖,但是从设计的角度来看,与Java代码相比,这是一个巨大的改进!

转到:隐式接口实现

在大多数OOP语言(Java,Scala,Kotlin等)中,类可以遵守合同,也称为接口 。 这样,客户端代码可以引用该接口,而不关心任何特定的实现。

publicinterfaceShape{

  floatarea();
  floatperimeter();

  defaultvoiddisplay(){
    System.out.println(this);
    System.out.println(perimeter());
    System.out.println(area());
  }
}

publicclassRectangleimplementsShape{

  publicfinalfloatwidth;
  publicfinalfloatheight;

  publicRectangle(floatwidth,floatheight){
    this.width=width;
    this.height=height;
  }

  @Override
  publicfloatarea(){
    returnwidth*height; (1)
  }

  @Override
  publicfloatperimeter(){
    return2*width+2*height; (1)
  }

  publicstaticvoidmain(String...args){
    varrect=newRectangle(2.0f,3.0f);
    rect.display();
  }
}
  1. 一个人应该使用BigDecimal来达到精确的目的-但这不是重点

重要的一点是:由于Rectangle实现Shape ,因此可以在Rectangle任何实例上调用Shape上定义的display()方法。

Go不是一种OOP语言:它没有类的概念。 它提供结构 ,并且功能可以与这种结构相关联。 它还提供了结构可以实现的接口

但是,Java实现接口的方法是明确的Rectangle类声明其实现Shape 。 相反,Go的方法是隐式的 。 实现接口所有功能的结构隐式实现此接口。

这将转换为以下代码:

packagemain

import(
 "fmt"
)

typeshapeinterface{ (1)
 area()float32
 perimeter()float32
}

typerectanglestruct{ (2)
 widthfloat32
 heightfloat32
}

func(rectrectangle)area()float32{ (3)
 returnrect.width*rect.height
}

func(rectrectangle)perimeter()float32{ (3)
 return2*rect.width+2*rect.height
}

funcdisplay(shapeshape){ (4)
 fmt.Println(shape)
 fmt.Println(shape.perimeter())
 fmt.Println(shape.area())
}

funcmain(){
 rect:=rectangle{width:2,height:3}
 display(rect) (5)
}
  1. 定义shape界面
  2. 定义rectangle结构
  3. 将两个shape函数都添加到rectangle
  4. display()函数仅接受shape
  5. 因为rectangle实现了shape所有功能,并且由于隐式实现,所以rect也是shape 。 因此,调用display()函数并将rect作为参数传递是完全合法的

Clojure:“依赖类型”

我以前的公司在Clojure投入了很多资金。 因此,我尝试学习该语言,甚至写了几篇文章来总结我对语言的理解。

Clojure在很大程度上受到LISP的启发。 因此,表达式用括号括起来,并且要执行的功能首先位于它们的内部。 另外,Clojure是一种动态类型化的语言:虽然有类型,但没有声明它们。

一方面,该语言提供了基于合同的编程。 可以指定前置条件和后置条件:在运行时对它们进行评估。 这样的条件可以进行类型检查, 例如,参数是字符串,布尔值等吗? -甚至可以更进一步,类似于_dependent类型

在计算机科学和逻辑中,从属类型是其定义取决于值的类型。 “整数对”是一种类型。 由于对值的依赖性,“第二对大于第一对的整数对”是从属类型。

—维基百科
https://zh.wikipedia.org/wiki/Dependent_type

它是在运行时强制执行的,因此不能真正称为依赖类型。 但是,这是我所涉猎的语言中最接近的一种。

之前,我曾详细地写过一个依赖于岗位的类型和基于契约的程序。

长生不老药:模式匹配

一些语言自称为提供模式匹配功能。 通常,模式匹配用于评估变量, 例如在Kotlin中:

varstatusCode:Int
valerrorMessage=when(statusCode){
  401->"Unauthorized"
  403->"Forbidden"
  500->"Internal Server Error"
  else->"Unrecognized Status Code"
}

此用法是类固醇的转换语句。 但是,通常,模式匹配的应用范围更加广泛。 在以下代码段中,将检查第一个常规的HTTP状态错误代码,如果未找到,则默认为更通用的错误消息:

valerrorMessage=when{
  statusCode==401->"Unauthorized"
  statusCode==403->"Forbidden"
  statusCode-400<100->"Client Error"
  statusCode==500->"Internal Server Error"
  statusCode-500<100->"Server Error"
  else->"Unrecognized Status Code"
}

不过,它是有限的。

Elixir是一种在Erlang OTP上运行的动态类型化语言,将模式匹配提升到了一个全新的水平。 Elixir的模式匹配可用于简单的变量解构:

{a,b,c}={:hello,"world",42}

将为a分配:hello ,向b分配“ world”,向c分配42。

它也可以用于集合的更高级的分解:

[head|tail]=[1,2,3]

head将被分配为1,而tail将被分配为[2, 3]

然而,对于函数重载甚至更是如此。 作为一种功能语言,Elixir没有用于循环的关键字( forwhile ):循环需要使用递归实现。

例如,让我们使用递归来计算List的大小。 在Java中,这很容易,因为有一个size()方法,但是Elixir API没有提供这种功能。 让我们以Elixir方式伪代码实现它-使用递归。

publicintlengthOf(List<?>item){
  returnlengthOf(0,items);
}

privateintlengthOf(intsize,List<?>items){
  if(items.isEmpty()){
    returnsize;
  }else{
    returnlengthOf(size+1,items.remove(0));
  }
}

这可以几乎逐行转换为Elixir:

deflength_of(list),do:length_of(0,list)

defplength_of(size,list)do
  if[]==listdo
    size
  else
    [_|tail]=list (1)
    length_of(size+1,tail)
  end
end
  1. 模式匹配与可变解构。 头值分配给_变量,这意味着以后无法引用它-因为它没有用。

但是,如前所述,Elixir模式匹配也适用于函数重载。 因此,写Elixir的名义方法是:

deflist_len(list),do:list_len(0,list)

defplist_len(size,[]),do:size (1)
defplist_len(size,list)do (2)
  [_|tail]=list
  list_len(size+1,tail)
end
  1. 如果列表为空,则调用此函数
  2. 否则调用此函数

请注意,模式是按照声明的顺序进行评估的:在上面的代码段中,Elixir首先评估具有空列表的函数,并且仅在不匹配的情况下评估第二个函数, 列表不为空。 如果要以相反的顺序声明函数,则每次都会在非空列表上进行匹配。

Python:理解

Python是一种动态类型的趋势语言。 就像Java中一样,Python通过for关键字提供循环。 以下片段循环遍历集合中的所有项目,并逐一打印它们。

fornin[1,2,3,4,5]:
  print(n)

要收集新集合中的所有项目,可以创建一个空集合,然后将每个项目添加到循环中:

numbers=[]
fornin[1,2,3,4,5]:
  numbers.append(n)
print(numbers)

但是,可以使用漂亮的Python功能: 进行理解 。 尽管它与标准循环使用相同的for关键字,但是for comprehension是实现相同结果的功能构造。

numbers=[nfornin[1,2,3,4,5]]
print(numbers)

上一个代码段的输出为[1, 2, 3, 4, 5]

也可以变换每个项目。 例如,以下代码片段将计算每个项目的平方:

numbers=[n**2fornin[1,2,3,4,5]]
print(numbers)

输出[1, 4, 9, 16, 25]

理解的好处是可以使用条件句。 例如,以下代码段将仅过滤偶数项,然后将它们平方:

numbers=[n**2fornin[1,2,3,4,5]ifn%2==0]
print(numbers)

输出为[4, 16]

最后,为了理解,允许使用笛卡尔积。

numbers=[a:nfornin[1,2,3]forain['a','b']]
print(numbers)

将会输出[('a', 1), ('b', 1), ('a', 2), ('b', 2), ('a', 3), ('b', 3)]

上面的理解也称为列表理解,因为它们旨在创建新列表。 地图理解非常相似,旨在创建...地图。

结论

尽管Java是一门不断发展的语言,但这是一件好事。 但是,其他语言中发现的方法也值得研究。 请记住,一种语言构成了人们对问题的思考方式以及解决方案的设计方式。 学习或至少熟悉其他语言是考虑其他观点的好方法。

翻译自: https://blog.frankel.ch/six-interesting-features-programming-languages/

c语言 有趣简单编程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值