注解configuration
本文介绍了动态语言的优缺点,倡导大家在享受动态语言的自由度时,也要尽可能地像静态语言那样思考,遵循一些规范和原则,避免一些隐患和错误。
原文链接:https://stackoverflow.blog/2023/01/19/adding-structure-to-dynamic-languages/
未经允许,禁止转载!
作者 | Daniel Orner 译者 | 明明如月责编 | 夏萌出品 | CSDN(ID:CSDNnews)过去很长一段时间内,大多数软件开发依赖的都是静态类型和编译型语言,如 C、C++ 以及 Java。当动态语言开始崭露头角时,最初它们常常被贬低为“玩具”语言,而 JavaScript 就是其中之一。然而,随着时间的推移,解释型动态编程语言的优势开始得到认同。
现今,尤其在网络应用程序领域,使用动态语言的频率几乎与使用静态语言相当。JavaScript 和 Python 常年稳居常年最受欢迎语言前五之列,同时其他如 PHP 和 Ruby 等语言也始终占据一席之地。
动态编程语言带来了多项优势:
它们是解释型的而非编译型的,无需在代码执行时额外的编译步骤和等待时间。
代码一般更为简洁,因为不需要花费大量时间在定义和转换类型上。
它们允许创建 领域特定语言 (DSLs),可以更自然地定义应用程序路由或配置。
通常可以在运行时动态修改或“猴子补丁”(即“动态打补丁”),方便地为第三方库的对象添加新功能。
可以容易地实现混合类型的集合,如数组和字典,这在静态类型语言中通常难以实现。
类型转换通常更为简便——无需为不同的输入参数类型写多份函数,可以设计一个函数,接受任何类型的参数并进行必要的类型转换。
元编程允许你轻松调整第三方代码,避免了漫长的分支、拉取请求和合并流程,这个过程可能会耗费数月甚至数年,取决于项目的规模。
你们中的细心人可能已经发现,这个列表中的每一项都既可以被视为优点,也可以作为缺点。让我们一一分析:
解释器无法像编译器那样全面地捕获问题。
不够精确的类型定义可能引发更多错误。
DSL(领域特定语言)可能引入混乱,增加你在理解应用和语言方面的心智负担。
如果任何人都能修改一个类型,他们可能会滥用本应只在内部使用的代码。
混合类型的集合的使用通常既不正确又混乱。
一个函数应用于多个类型可能导致混乱。
对第三方类进行动态打补丁可能导致代码过时和升级难。
随着动态语言越来越受欢迎,业界对如何解决这些问题进行了热议。我对动态语言的感知也在不断变化,最初对它们所带来的自由感到激动,但后来开始意识到其中潜在的问题。
我现在主要使用 Ruby,可能是最“动态”的流行动态语言之一。然而,即使在使用 Ruby 的过程中,我也发现了一套实践,我认为它们可以帮助缓解动态编程的一些缺点。
充分发挥类型提示的作用过去十年间,主流的动态编程语言都陆续引入了类型提示功能。其中最著名、使用最广泛的无疑是 TypeScript,它是 JavaScript 的超集,需要一个编译器将其代码转化为标准的 JavaScript。Python 和 PHP 在语言层面都引入了类型提示,即使是 Ruby 也试图进行了 RBS 和 Sorbet 项目(虽然这两个项目似乎并未得到广泛的支持)。
类型提示是使动态语言走向静态化的最直接路径。实际上,这让你能够享受最好的两个世界:编写动态代码的同时,需要更加谨慎地确定你期待获取和使用的数据类型。
有趣的是,优秀的类型提示系统往往比静态语言的类型系统更为复杂。以 Java 为例,你无法声明一个对象属性可以是整数 或者 字符串——但在 TypeScript 中,通过联合类型,这个操作就变得非常简单:
printLabel = (label: string|number) => string { console.log(`Please fill out ${label}`);}这是因为类型提示系统意图并不是要把动态语言变成静态语言,而是要让你用一种机器可以理解和执行的方式来记录你对类型的期望。这样,你可以在编译时或运行时发现并修复类型错误,提高代码的健壮性和可读性。
最后,需要指出的是,大部分类型提示系统都允许进行 渐进式类型化。在这种模式下,你可以逐个文件开启类型提示,而无需一次性转换整个代码库。你可以借助这个特性,逐步将你的代码迁移到你的类型系统中,而无需在一个项目中一次性完成所有转换。
处理非结构化数据:字典的运用在动态编程语言中,字典或哈希表的使用是一种常见的实践,它们被用于处理非结构化数据。当需要从函数返回数据或向函数传递选项时,字典通常是首选的数据结构:
def configure(options={}) self.logger = options[:logger] self.host_name = options[:host_name]end或:
return { count: 5, average: 10}由于字典可以用来存储任意的键值对,所以它们无法提供类型提示。使用字典来表达已知的数据会使得类型推导和错误查找变得困难。在第一个例子中,如果你不慎将 :loger 作为 :logger 的输入,错误将无法被抛出,而仅仅是把 logger 设为 null,这并不是你所期望的,因为这是一个调用代码中的错误,而不是数据中的错误。
对于支持接口或鸭子类型(动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。)的类型提示系统,如 TypeScript,你可以继续使用字典:
interface CountResult { count: number; average: number;}getCount : CountResult = () => { return { count: 5, average: 10} };对于不支持该特性的编程语言,你可以选择使用结构体或数据类,这些类型简单且通常是不可变的,包含了一组字段:
ConfigurationOptions = Struct.new(:logger, :host_name)def configure(options=ConfigurationOptions.new) self.logger = options.logger self.host_name = options.host_nameend从索引表示法转为点表示法这一简单步骤引入了一种类型安全性级别。这样的转变可以增强代码的健壮性,即使在完全没有类型提示系统的情况下也可以实现。如果某个方法不存在,代码将会抛出一个错误,让你可以立即发现问题。
即使你没有使用类型提示系统,你也可以注释你的字段。许多 IDE 都能从这些注释中获取信息,进而实现自动补全。虽然这可能使定义变得更冗长,但是却更易于推理:
class ConfigurationOptions # @return [Logger] attr_accessor :logger # @return [String] attr_accessor :host_name明确地表达你的代码的意图和逻辑静态语言强调明确性,有时候甚至给人过于严格的印象。你想知道一段代码在做什么?那就简单地用 ctrl+点击进入,然后沿着调用栈向下追溯。这里没有任何难以理解的“神秘”操作。对于动态语言以及像 C 这样允许定义宏的语言,这种追踪过程就变得更加困难。动态语言经常无法通过“grep 测试” —— 我在阅读代码时,如果看到一个方法或特定的语法,我能否通过搜索整个代码库或者依赖来找到它的定义?如果找不到,那可能就意味着存在过多的元编程。
实际上,应该进行元编程或反射的只有框架本身。设计自己的内部框架是完全没有问题的,特别是它针对解决你的团队或公司特有的常见问题,那就是框架的最佳应用。但是,你不能假设他人理解你提供给他们的每一个细节影响,除非这些影响是明确地声明的。
如何判断自己的代码是否足够明确呢?当面对一个问题,你或许会有这样的想法,“我可以简洁地解决这个问题,或者我可以花费时间将所有的细节一一呈现出来,尽管这会花费我更多的时间。” 在这种情况下,你应该选择花费更多的时间来呈现细节。
让我们看个例子。在我们的 Rails 应用中,有许多与传单相关的工作类型。定义这些关联的一种方式需要遍历这些工作类型:
JOB_TYPES = [:process_image, :upload_image, :process_tagging]JOB_TYPES.each do |type| has_many "#{type}_jobs"end这段代码能够正常工作,但如果我在代码库的某个地方看到 flyer.process_image_jobs,我应该如何知道它来自何处呢?
更直接的方式虽然工作量稍大,但是却更清晰:
has_many :process_image_jobshas_many :upload_image_jobshas_many :process_tagging_jobs总的来说,你应该遵循最少惊讶原则。具体来说就是:
不要对你无权修改的对象,尤其是基础类型,进行动态打补丁或更改行为。
不要通过编程的方式创建方法;确保你可以在你的代码库。
尽量不要使用隐式状态(例如在类的作用域之外使用 JavaScript 的 this 关键字)。明确指出正在操作的是什么对象。
避免隐式地自动关联代码(例如,通过读取特定的文件结构,StimulusJS 就是这样做的,这是我对其它一些优秀的包的不满之处)。
当然,有些情况下我们可能需要一些“花哨”的操作,但是你需要明智地选择使用的场景!
要经得住诱惑动态语言给你很多自由,但也有很多风险,就像有句话说的,给你无限的空间让你自取灭亡。你应该享受自由,但也要尽可能地像静态语言那样思考,遵循一些规范和原则,避免一些隐患和错误。
对于如何更好地使用动态语言,你有何经验?欢迎在评论区交流经验。
","gnid":"903eacb54baab6312","img_data":[{"flag":2,"img":[{"desc":"","height":"80","s_url":"https://p0.ssl.img.360kuai.com/t0160bfdc18dd41df77_1.gif","title":"","url":"https://p0.ssl.img.360kuai.com/t0160bfdc18dd41df77.gif","width":"640"}]}],"original":0,"pat":"art_src_1,fts0,sts0","powerby":"hbase","pub_time":1689674468000,"pure":"","rawurl":"http://zm.news.so.com/848f6bbfab7194d08cfe37672e54d00a","redirect":0,"rptid":"4ad55bf31d8cfcc8","rss_ext":[],"s":"t","src":"CSDN","tag":[{"clk":"ktechnology_1:java","k":"java","u":""}],"title":"最小化动态编程语言的缺点
柯政傅2978人心惟危,道心惟微,惟精惟一,允执厥中.出自哪里 -
骆聪涛17114568187 ______[答案] “人心惟危,道心惟微;惟精惟一,允执厥中.”这十六个字便是儒学乃至中国文化传统中著名的“十六字心传”.古文《尚... 此乃对十六宇心传之“惟精惟一,允执厥中”的精辟注解,由此演变出《中庸》之孔门儒学传授心法. “天命之谓性;率性之...
柯政傅2978财色名食睡,地狱五条根 -
骆聪涛17114568187 ______ 人贪著色声香味触五欲之境,即财色名食睡;此为地狱五条根,条条皆通入地狱.譬如: (一)贪财者:不择手段去赚取金钱,不顾仁义道德,也不管金钱之来源是否正当,终日'心为钱役',种下堕地狱之种子. (二)贪色:美色是众生轮...
柯政傅2978《陈涉世家》中“楚人怜之”的“怜”为何意 -
骆聪涛17114568187 ______ 刚复习了《陈涉世家》,我发现“楚人怜之”中的“怜”字意思发生了变化,原来翻译为“爱戴”,如今课本变为了“哀怜、怜悯”. 原文为:项燕为楚将,数有功,爱士卒,楚人怜之.或以为死,或以为亡.此句的意思是说“项燕是楚国的将...
柯政傅2978三国演义白话版(全).txt -
骆聪涛17114568187 ______ 链接: https://pan.baidu.com/s/1aTeLUyOSTB5iSMdfajHFhw 提取码: 9xbs 复制这段内容后打开百度网盘手机App,操作更方便哦 作品简介:《三国演义》(全名为《三国志通俗演义》,又称《三国志演义》)是元末明初小说家罗贯中根据陈寿《三国志》和裴松之注解以及民间三国故事传说经过艺术加工创作而成的长篇章回体历史演义小说,与《西游记》《水浒传》《红楼梦》并称为中国古典四大名著. 该作品成书后有嘉靖壬午本等多个版本传于世,到了明末清初,毛宗岗对《三国演义》整顿回目、修正文辞、改换诗文,该版本也成为诸多版本中水平最高、流传最广的版本.
柯政傅2978求黑莲花攻略手册txt百度云? -
骆聪涛17114568187 ______ 链接: https://pan.baidu.com/s/1JGLn264fLZZaKUc-vTrTUw 提取码: xumj《黑莲花攻略手册》 作者:白羽摘雕弓 文案: 这个世界妖物横行,正待英雄儿女书写传奇. 可惜,你不是冰清玉洁的女主,不是身娇体贵的反派女二,而是人人讨厌的炮灰女三. 原身暗恋男主,暗害女主,终其一生为男女主角的爱情之路使绊子,让姐控男二踩在脚下,用生命为“蠢”作注解. “你的意思是抢了女主的男人,我就成功了” “抱歉,您的攻略对象他是女主的弟弟.”
柯政傅2978Del 电脑系统英文翻译:<6> Pnp/Pcl Configurat ions ? -
骆聪涛17114568187 ______ 即插即用/ Pcl Configurat离子
柯政傅2978我想装xp系统 进入了 SATA Configurat ion 里面 怎样改不了接口!
骆聪涛17114568187 ______ 要先改1个选项才可以致因而哪一个我也忘记了