function/bind的救赎(上)

2023-11-01

本文转自孟岩的博客

http://blog.csdn.net/myan/article/details/5928531

这是那篇C++0X的正文。太长,先写上半部分发了。

Function/bind可以是一个很简单的话题,因为它其实不过就是一个泛型的函数指针。但是如果那么来谈,就没意思了,也犯不上写这篇东西。在我看来,这个事情要讲的话,就应该讲透,讲到回调(callback)、代理(delegate)、信号(signal)和消息传递(messaging)的层面,因为它确实是太重要了。这个话题不但与面向对象的核心思想密切相关,而且是面向对象两大流派之间交锋的中心。围绕这个问题的思考和争论,几乎把20年来所有主流的编程平台和编程语言都搅进来了。所以,如果详尽铺陈,这个话题直接可以写一本书。

写书我当然没那个水平,但这个题目确实一直想动一动。然而这个主题实在太大,我实在没有精力把它完整的写下来;这个主题也很深,特别是涉及到并发环境有关的话题,我的理解还非常肤浅,总觉得我认识的很多高手都比我更有资格写这个话题。所以犹豫了很久,要不要现在写,该怎么写。最后我觉得,确实不能把一篇博客文章写成一本20年面向对象技术史记,所以决定保留大的架构,但是对其中具体的技术细节点到为止。我不会去详细地列举代码,分析对象的内存布局,画示意图,但是会把最重要的结论和观点写下来,说得好听一点是提纲挈领,说的不好听就是语焉不详。但无论如何,我想这样一篇东西,一是谈谈我对这个事情的看法,二是“抛砖引玉”,引来高手的关注,引出更深刻和完整的叙述。

下面开始。

0. 程序设计有一个范式(paradigm)问题。所谓范式,就是组织程序的基本思想,而这个基本思想,反映了程序设计者对程序的一个基本的哲学观,也就是说,他认为程序的本质是什么,他认为一个大的程序是由什么组成的。而这,又跟他对于现实世界的看法有关。显然,这样的看法不可能有很多种。编程作为一门行业,独立存在快60年了,但是所出现的范式不过三种——过程范式、函数范式、对象范式。其中函数范式与现实世界差距比较大,在这里不讨论。而过程范式和对象范式可以视为对程序本质的两种根本不同的看法,而且能够分别在现实世界中找到相应的映射。

  • 过程范式认为,程序是由一个又一个过程经过顺序、选择和循环的结构组合而成。反映在现实世界,过程范式体现了劳动分工之前“全能人”的工作特点——所有的事情都能干,所有的资源都是我的,只不过得具体的事情得一步步地来做。
  • 对象范式则反映了劳动分工之后的团队协作的工作特点——每个人各有所长,各司其职,有各自的私有资源,工件和信息在人们之间彼此传递,最后完成工作。因此,对象范式也就形成了自己对程序的看法——程序是由一组对象组成,这些对象各有所能,通过消息传递实现协作。

对象范式与过程范式相比,有三个突出的优势,第一,由于实现了逻辑上的分工,降低了大规模程序的开发难度。第二,灵活性更好——若干对象在一起,可以灵活组合,可以以不同的方式协作,完成不同的任务,也可以灵活的替换和升级。第三,对象范式更加适应图形化、网络化、消息驱动的现代计算环境。

所以,较之于过程范式,对象范式,或者说“面向对象”,确实是更具优势的编程范式。最近看到一些文章抨击面向对象,说面向对象是胡扯,我认为要具体分析。对面向对象的一部分批评,是冲着主流的“面向对象”语言去的,这确实是有道理的,我在下面也会谈到,而且会骂得更狠。而另一个批评的声音,主要而来自STL之父Alex Stepanov,他说的当然有他的道理,不过要知道该牛人是前苏联莫斯科国立罗蒙诺索夫大学数学系博士,你只要翻翻前苏联的大学数学教材就知道了,能够在莫大拿到数学博士的,根本就是披着人皮的外星高等智慧。而我们编写地球上的程序,可能还是应该以地球人的观点为主。

1. 重复一遍对象范式的两个基本观念:

  • 程序是由对象组成的;
  • 对象之间互相发送消息,协作完成任务;

请注意,这两个观念与后来我们熟知的面向对象三要素“封装、继承、多态”根本不在一个层面上,倒是与再后来的“组件、接口”神合。

2. 世界上第一个面向对象语言是Simula-67,第二个面向对象语言是Smalltalk-71。Smalltalk受到了Simula-67的启发,基本出发点相同,但也有重大的不同。先说相同之处,Simula和Smalltalk都秉承上述对象范式的两个基本观念,为了方便对象的构造,也都引入了类、继承等概念。也就是说,类、继承这些机制是为了实现对象范式原则而构造出来的第二位的、工具性的机制,那么为什么后来这些第二位的东西篡了主位,后面我会再来分析。而Simula和Smalltalk最重大的不同,就是Simula用方法调用的方式向对象发送消息,而Smalltalk构造了更灵活和更纯粹的消息发送机制。

具体的说,向一个Simula对象中发送消息,就是调用这个对象的一个方法,或者称成员函数。那么你怎么知道能够在这个对象上调用这个成员函数呢?或者说,你怎么知道能够向这个对象发送某个消息呢?这就要求你必须确保这个对象具有合适的类型,也就是说,你得先知道哦这个对象是什么,才能向它发消息。而消息的实现方式被直接处理为成员函数调用,或虚函数调用。

而Smalltalk在这一点上做了一个历史性的跨越,它实现了一个与目标对象无关的消息发送机制,不管那个对象是谁,也不管它是不是能正确的处理一个消息,作为发送消息的对象来说,可以毫无顾忌地抓住一个对象就发消息过去。接到消息的对象,要尝试理解这个消息,并最后调用自己的过程来处理消息。如果这个消息能被处理,那个对象自然会处理好,如果不能被处理,Smalltalk系统会向消息的发送者回传一个doesNotUnderstand消息,予以通知。对象不用关心消息是如何传递给另一个对象的,传递过程被分离出来(而不是像Simula那样明确地被以成员函数调用的方式实现),可以是在内存中复制,也可以是进程间通讯。到了Smalltalk-80时,消息传递甚至可以跨越网络。

为了方便后面的讨论,不妨把源自Simula的消息机制称为“静态消息机制”,把源自Smalltalk的消息机制称为“动态消息机制”

Simula与Smalltalk之间对于消息机制的不同选择,主要是因为两者于用途。前者是用于仿真程序开发,而后者用于图形界面环境构建,看上去各自合情合理。然而,就是这么一点简单的区别,却造成了巨大的历史后果。

3. 到了1980年代,C++出现了。Bjarne Stroustrup在博士期间深入研究过Simula,非常欣赏其思想,于是就在C语言语法的基础之上,几乎把Simula的思想照搬过来,形成了最初的C++。C++问世以之初,主要用于解决规模稍大的传统类型的编程问题,迅速取得了巨大的成功,也证明了对象范式本身所具有的威力。

大约在同期,Brad Cox根据Smalltalk的思想设计了Objective-C,可是由于其语法怪异,没有流行起来。只有Steve Jobs这种具有禅宗美学鉴赏力的世外高人,把它奉为瑰宝,与1988年连锅把Objective-C的团队和产品一口气买了下来。

4. 就在同一时期,GUI成为热门。虽然GUI的本质是对象范型的,但是当时(1980年代中期)的面向对象语言,包括C++语言,还远不成熟,因此最初的GUI系统无一例外是使用C和汇编语言开发的。或者说,最初的GUI开发者硬是用抽象级别更低的语言构造了一个面向对象系统。熟悉Win32 SDK开发的人,应该知道我在说什么。

5. 当时很多人以为,如果C++更成熟些,直接用C++来构造Windows系统会大大地容易。也有人觉得,尽管Windows系统本身使用C写的,但是其面向对象的本质与C++更契合,所以在其基础上包装一个C++的GUI framework一定是轻而易举。可是一动手人们就发现,完全不是那么回事。用C++开发Windows框架难得要死。为什么呢?主要就是Windows系统中的消息机制实际上是动态的,与C++的静态消息机制根本配合不到一起去。在Windows里,你可以向任何一个窗口发送消息,这个窗口自己会在自己的wndproc里来处理这个消息,如果它处理不了,就交给default window/dialog proc去处理。而在C++里,你要向一个窗口发消息,就得确保这个窗口能处理这个消息,或者说,具有合适的类型。这样一来的话,就会导致一个错综复杂的窗口类层次结构,无法实现。而如果你要让所有的窗口类都能处理所有可能的消息,且不论这样在逻辑上就行不通(用户定义的消息怎么处理?),单在实现上就不可接受——为一个小小的不同就得创造一个新的窗口类,每一个小小的窗口类都要背上一个多达数百项的v-table,而其中可能99%的项都是浪费,不要说在当时,就是在今天,内存数量非常丰富的时候,如果每一个GUI程序都这么搞,用户也吃不消。

6. 实际上C++的静态消息机制还引起了更深严重的问题——扭曲了人们对面向对象的理解。既然必须要先知道对象的类型,才能向对象发消息,那么“类”这个概念就特别重要了,而对象只不过是类这个模子里造出来的东西,反而不重要。渐渐的,“面向对象编程”变成了“面向类编程”,“面向类编程”变成了“构造类继承树”。放在眼前的鲜活的对象活动不重要了,反而是其背后的静态类型系统成为关键。“封装、继承”这些第二等的特性,喧宾夺主,俨然成了面向对象的要素。每个程序员似乎都要先成为领域专家,然后成为领域分类学专家,然后构造一个完整的继承树,然后才能new出对象,让程序跑起来。正是因为这个过程太漫长,太困难,再加上C++本身的复杂度就很大,所以C++出现这么多年,真正堪称经典的面向对象类库和框架,几乎屈指可数。很多流行的库,比如MFC、iostream,都暴露出不少问题。一般程序员总觉得是自己的水平不够,于是下更大功夫去练剑。殊不知根本上是方向错了,脱离了对象范式的本质,企图用静态分类法来对现实世界建模,去刻画变化万千的动态世界。这么难的事,你水平再高也很难做好。

可以从一个具体的例子来理解这个道理,比如在一个GUI系统里,一个 Push Button 的设计问题。事实上在一个实际的程序里,一个 push button 到底“是不是”一个 button,进而是不是一个 window/widget,并不重要,本质上我根本不关心它是什么,它从属于哪一个类,在继承树里处于什么位置,只要那里有这么一个东西,我可以点它,点完了可以发生相应的效果,就可以了。可是Simula –> C++ 所鼓励的面向对象设计风格,非要上来就想清楚,a Push Button is-a Button, a Buttonis-a Command-Target Control, a Command-Target Control is-a Control, a Control is-a Window. 把这一圈都想透彻之后,才能 new 一个 Push Button,然后才能让它工作。这就形而上学了,这就脱离实际了。所以很难做好。你看到 MFC 的类继承树,觉得设计者太牛了,能把这些层次概念都想清楚,自己的水平还不够,还得修炼。实际上呢,这个设计是经过数不清的失败和钱磨出来、砸出来的,MFC的前身 Afx 不是就失败了吗?1995年还有一个叫做 Taligent 的大项目,召集了包括 Eric Gamma 在内的一大堆牛人,要用C++做一个一统天下的application framework,最后也以惨败告终,连公司都倒闭了,CEO车祸身亡,牛人们悉数遣散。附带说一下,这个Taligent项目是为了跟NextSTEP和Microsoft Cairo竞争,前者用Objective-C编写,后来发展为Cocoa,后者用传统的Win32 + COM作为基础架构,后来发展为Windows NT。而Objective-C和COM,恰恰就在动态消息分派方面,与C++迥然不同。后面还会谈到。

客观地说,“面向类的设计”并不是没有意义。来源于实践又高于实践的抽象和概念,往往能更有力地把握住现实世界的本质,比如MVC架构,就是这样的有力的抽象。但是这种抽象,应该是来源于长期最佳实践的总结和提高,而不是面对问题时主要的解决思路。过于强调这种抽象,无异于假定程序员各个都是哲学家,具有对现实世界准确而深刻的抽象能力,当然是不符合实际情况的。结果呢,刚学习面向对象没几天的程序员,对眼前鲜活的对象世界视而不见,一个个都煞有介事地去搞哲学冥想,企图越过现实世界,去抽象出其背后本质,当然败得很惨。

其实C++问世之后不久,这个问题就暴露出来了。第一个C++编译器 Cfront 1.0 是单继承,而到了 Cfront 2.0,加入了多继承。为什么?就是因为使用中人们发现逻辑上似乎完美的静态单继承关系,碰到复杂灵活的现实世界,就破绽百出——蝙蝠是鸟也是兽,水上飞机能飞也能游,它们该如何归类呢?本来这应该促使大家反思继承这个机制本身,但是那个时候全世界陷入继承狂热,于是就开始给继承打补丁,加入多继承,进而加入虚继承,。到了虚继承,明眼人一看便知,这只是一个语法补丁,是为了逃避职责而制造的一块无用的遮羞布,它已经完全已经脱离实践了——有谁在事前能够判断是否应该对基类进行虚继承呢?

到了1990年代中期,问题已经十分明显。UML中有一个对象活动图,其描述的就是运行时对象之间相互传递消息的模型。1994年Robert C. Martin在《Object-Oriented C++ Design Using Booch Method》中,曾建议面向对象设计从对象活动图入手,而不是从类图入手。而1995年出版的经典作品《Design Patterns》中,建议优先考虑组合而不是继承,这也是尽人皆知的事情。这些迹象表明,在那个时候,面向对象社区里的思想领袖们,已经意识到“面向类的设计”并不好用。只可惜他们的革命精神还不够。

7. 你可能要问,Java 和.NET也是用继承关系组织类库,并进行设计的啊,怎么那么成功呢?这里有三点应该注意。第一,C++的难不仅仅在于其静态结构体系,还有很多源于语言设计上的包袱,比如对C的兼容,比如没有垃圾收集机制,比如对效率的强调,等等。一旦把这些包袱丢掉,设计的难度确实可以大大下降。第二,Java和.NET的核心类库是在C++十几年成功和失败的经验教训基础之上,结合COM体系优点设计实现的,自然要好上一大块。事实上,在Java和.NET核心类库的设计中很多地方,体现的是基于接口的设计,和真正的基于对象的设计。有了这两个主角站台,“面向类的设计”不能喧宾夺主,也能发挥一些好的作用。第三,如后文指出,Java和.NET中分别对C++最大的问题——缺少对象级别的delegate机制做出了自己的回应,这就大大弥补了原来的问题。

尽管如此,Java还是沾染上了“面向类设计”的癌症,基础类库里就有很多架床叠屋的设计,而J2EE/Java EE当中,这种形而上学的设计也很普遍,所以也引发了好几次轻量化的运动。这方面我并不是太懂,可能需要真正的Java高手出来现身说法。我对Java的看法以前就讲过——平台和语言核心非常好,但风气不好,崇尚华丽繁复的设计,装牛逼的人太多。

至于.NET,我听陈榕介绍过,在设计.NET的时候,微软内部对于是否允许继承爆发了非常激烈的争论。很多资深高人都强烈反对继承。至于最后引入继承,很大程度上是营销需要压倒了技术理性。尽管如此,由于有COM的基础,又实现了非常彻底的delegate,所以 .NET 的设计水平还是很高的。它的主要问题不在这,在于太急于求胜,更新速度太快,基础不牢。当然,根本问题还是微软没有能够在Web和Mobile领域里占到多大的优势,也就使得.NET没有用武之地。

8. COM。COM的要义是,软件是由COM Components组成,components之间彼此通过接口相互通讯。这是否让你回想起本文开篇所提出的对象范型的两个基本原则?有趣的是,在COM的术语里,“COM Component ” 与“object ”通假,这就使COM的心思昭然若揭了。Don Box在Essential COM里开篇就说,COM是更好的C++,事实上就是告诉大家,形而上学的“面向类设计”不好使,还是回到对象吧。

用COM开发的时候,一个组件“是什么”不重要,它具有什么接口,也就是说,能够对它发什么消息,才是重要的。你可以用IUnknown::QueryInterface问组件能对哪一组消息作出反应。向组件分派消息也不一定要被绑定在方法调用上,如果实现了 IDispatch,还可以实现“自动化”调用,也就是COM术语里的 Automation,而通过 列集(mashal),可以跨进程、跨网络向另一组件发送消息,通过 moniker,可以在分布式系统里定位和发现组件。如果你抱着“对象——消息”的观念去看COM的设计,就会意识到,整个COM体系就是用规范如何做对象,如何发消息的。或者更直白一点,COM就是用C/C++硬是模拟出一个Smalltalk。而且COM的概念世界里没有继承,就其纯洁性而言,比Smalltalk还Smalltalk。在对象泛型上,COM达到了一个高峰,领先于那个时代,甚至于比它的继任.NET还要纯洁。

COM的主要问题是它的学习难度和安全问题,而且,它过于追求纯洁性,完全放弃了“面向类设计” 的机制,显得有点过。

9. 好像有点扯远了,其实还是在说正事。上面说到由于C++的静态消息机制,导致了形而上学的“面向类的设计”,祸害无穷。但实际上,C++是有一个补救机会的,那就是实现对象级别的delegate机制。学过.NET的人,一听delegate这个词就知道是什么意思,但Java里没有对应机制。在C++的术语体系里,所谓对象级别delegate,就是一个对象回调机制。通过delegate,一个对象A可以把一个特定工作,比如处理用户的鼠标事件,委托给另一个对象B的一个方法来完成。A不必知道B的名字,也不用知道它的类型,甚至都不需要知道B的存在,只要求B对象具有一个签名正确的方法,就可以通过delegate把工作交给B的这个方法来执行。在C语言里,这个机制是通过函数指针实现的,所以很自然的,在C++里,我们希望通过指向成员函数的指针来解决类似问题。

然而就在这个问题上,C++让人扼腕痛惜。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

function/bind的救赎(上) 的相关文章

  • 使用 Crypto++ 和 .NET 的 CFB 模式下的 TripleDES

    我正在尝试使用 TripleDES 使用 C 应用程序获得相同的结果 该应用程序具有Crypto https www cryptopp com 和 NET应用程序使用三重DESCryptoServiceProvider https msdn
  • 为什么smtpclient发送的邮件没有出现在已发送项目中

    我已经实现了一个通过 Net SmtpClient 发送电子邮件的服务器 邮件发送代码如下 private static MailMessage SendMail string to string subject string body M
  • 使用 system.reflection 列出类字段

    我需要获取一个列表来存储类中的所有字段 值 这个班级只是一些公共的const string我在下面粘贴的变量 public class HTDB Cols public class TblCustomers public const str
  • 如何使用 WinAPI 读取 MessageBox 文本

    如何读取标准Win消息框 Info 的消息 Using SendMessage this HandleControl WM GETTEXT builder Capacity builder 我只能读取消息框的标题或按钮的文本 但不能读取消息
  • .NET ServiceModel.Syndicate - 更改 RSS 源的编码

    我正在尝试解决我在以下位置生成的所有 RSS 源的错误http captainobvio us http captainobvio us在 Internet Explorer 版本 8 和 9 中产生以下错误 进给代码错误 从当前切换 编码
  • 无法找到 .NET Core 项目

    我正在关注 c 的 brackeys 教程here https www youtube com watch v N775KsWQVkw 但在 7 55 时 我弹出一条消息 无法找到 NET Core 项目 未生成资产 我已经做了布雷基在那一
  • 如何将当前应用程序域的程序集动态加载到c#项目中?

    我正在尝试加载第三方assemblies 动态地到项目并使用reflection创建其类型的实例 I used Assembly LoadFrom Assembly1 dll Assembly LoadFrom Assembly2 dll
  • 添加到 .NET 任务栏中的右键单击应用程序菜单

    大多数应用程序只有 恢复 移动 调整大小 最小化 最大化和关闭 但是MS SQL提供了额外的选项 帮助 自定义视图 按照这些思路 是否可以添加到任务栏中应用程序的右键单击菜单 注 我是not指通知区域中时钟旁边的图标 这是一个更简单的ans
  • 使用 TCP 套接字在本地代理视频

    我一直对向媒体浏览器添加对视频播客的支持非常感兴趣 我希望用户能够浏览可用的视频播客并从互联网上流式传输它们 这真的很容易 因为媒体播放器等将愉快地播放存在于云中的文件 问题是我想在本地缓存这些文件 因此同一集的后续观看将不涉及流式传输 而
  • 带有嵌入 Flash 视频的 PDF 示例?

    有谁知道我在哪里可以查看嵌入 Flash 视频的 PDF 示例 我知道问这个问题很愚蠢 因为你会认为任何面向技术的用户都应该能够使用谷歌找到一个 但我真的找不到 我的另一个问题是 使用 C 中的 API 将 Flash 视频嵌入 PDF 文
  • 更改实体的可访问性

    我想建立一个内部实体 我已将实体 其标量属性和导航属性更改为内部 当我尝试构建它时出现此错误 错误 6036 EntityType 文件 具有 内部 可访问性 EntitySet 文件 具有具有 公共 可访问性的 get 属性 Entity
  • 从 AuthorizeAttribute 继承的属性不起作用

    我目前正在尝试根据用户角色在新的 ASP MVC 5 应用程序中实现安全性 目标是防止用户在没有特定角色 或更高角色 的情况下访问某些控制器或控制器方法 根据到目前为止我所读到的问题 我创建了一个继承 AuthorizeAttribute
  • .NET 或 Windows 同步原语性能规范

    我目前正在写一篇科学文章 我需要非常准确地引用 有人可以向我指出 MSDN MSDN 文章 一些已发表的文章来源或一本书 我可以在其中找到 Windows 或 NET 同步原语的性能比较 我知道这些是按性能降序排列的 互锁 API 关键部分
  • 从 .NET 文本中提取关键字

    我需要计算每个关键字在字符串中重复出现的次数 并按最高次数排序 NET 代码中用于此目的的最快算法是什么 编辑 下面的代码将唯一标记与计数分组 string target src Split new char var results tar
  • 如何更改 Settings.settings 值的值

    我有一个简单的控制台应用程序 每天运行 由 Windows 任务计划程序调用 并且取决于每次应用程序运行时递增的值 为了保留这个值 我选择使用 Settings Settings 文件 因此 我有一个名为 RunNumber 和 Scope
  • 将参数传递给模板类型的 C# 泛型 new()

    添加到列表时 我试图通过其构造函数创建一个 T 类型的新对象 我收到编译错误 错误消息是 T 创建变量实例时无法提供参数 但我的类确实有一个构造函数参数 我怎样才能做到这一点 public static string GetAllItems
  • 如何让CQRS适应项目? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我发现了一个新术语 名叫CQRS 命令查询职责分离 http martinfowler com bliki CQRS html其中指出 概念模型
  • .Net 6 控制台应用程序:WebApplication.CreateBuilder 与 Host.CreateDefaultBuilder

    我正在研究 NET 6 并希望构建一个简单的控制台应用程序 并进行一些依赖项注入 据我所知 为了使启动 现在只是程序 文件更具可读性 已经做了很多工作 让我有点困惑的是 所有改进似乎都是针对 API 项目中使用的 WebApplicatio
  • .net 中的计时器合并

    Windows 7 引入了计时器合并 提高了能源效率 哪些托管 API 公开了计时器容差 似乎利用此功能的唯一方法是 p invoke设置等待定时器 http msdn microsoft com en us library windows
  • 如何在我的应用程序中使用 Windows Key

    Like Windows Key E Opens a new Explorer Window And Windows Key R Displays the Run command 如何在应用程序的 KeyDown 事件中使用 Windows

随机推荐

  • 关于==和equals的区别和联系,面试这么回答就可以

    长篇大论的话 我这里就不多写了 相信大家入门java 的时候就知道个大概了 这里想表述的是 如果面试官问你 关于 和equals的区别 该怎么回答完美呢 可以这样说 总结的来说 1 对于 比较的是值是否相等 如果作用于基本数据类型的变量 则
  • vcomp140.dll丢失怎样修复?多种方法教你修复

    vcomp140 dll丢失算是一个比较常见的异常事件 在使用电脑的时候 有时候弹窗出现由于找不到vcomp140 dll 无法继续执行代码等 这种都是属于vcomp140 dll文件丢失 今天我们主要针对这个情况来给大家说说vcomp14
  • 谁在爬我的网站?我要“炸”了他

    如果你曾经搭建过自己的网站 那么你一定对网络爬虫感到无比的烦恼 这些爬虫每天都在大量的访问你的网站 频繁且毫无节制地消耗你的服务器资源 那么 今天我们就来探讨一下 如何 干死 这些爬虫的服务器 注意 本文所讨论的内容仅供技术交流 不涉及任何
  • jquery的layer打开iframe,通过ajax提交iframe表单

    addOption click function thisId var index1 layer open type 2 area 850px 450px maxmin true title 添加项 btn 确定 取消 content In
  • Centos下环境变量

    文章内容如下 1 什么是环境变量 2 如何通过程序获取环境变量 3 常识规律 一 环境变量的定义 环境变量就是指一段路径 定义环境变量主要是为了方便的执行程序 添加环境变量的方法是export PATH PATH A B export PA
  • 12.示例程序(定时器定时中断&定时器外部时钟)

    目录 定时中断和时钟源选择相关库函数使用 1 定时器初始化配置 2 参数 PSC ARR等 更改函数 在程序运行过程中修改 3 使用定时器库函数的一些细节 定时器定时中断实例 定时器外部时钟选择 知识点get 滤波器工作原理 可以滤掉信号的
  • python爬虫处理滑块验证_Python 爬虫进阶必备

    今日网站 aHR0cHM6Ly9idWxsZXRpbi5jZWJwdWJzZXJ2aWNlLmNvbS8 这个网站是比较简单的滑块验证码 没有涉及指纹 轨迹以及 JS 的加密 但是有助于进一步了解滑块验证码的具体实现和分析流程 所以作为 C
  • J2EE之集合框架

    集合框架01 0 UML 统一建模语言 1 Collection接口 1 1 集合框架的顶级接口 1 2 是Set和List的父接口 1 3 但不是Map的父接口 集合中只能添加引用类型数据 2 List接口 2 1 特点 有序 对象可以重
  • 解决centOS8下Unit network-manager.service not found的问题

    systemctl restart NetworkManager 使用上面的命令即可
  • armbian打印服务器恩山无线,刷了armbian后用cups共享打印非常爽

    另楼主我输入apt get install hannah foo2zjs printer driver foo2zjs common printer driver foo2zjs命令返回有错误啊何解Setting up dc 1 06 95
  • 借助PLC-Recorder,西门子PLC S7-1200实现4ms准确周期采集的方法(带时间戳采集)

    目录 1 测试条件 2 测试结论 3 PLC的发送程序 4 PLC连接配置 5 PLC Recorder侧的通讯设置 6 PLC Recorder的通道配置 7 PLC Recorder的变量配置 8 正常通讯情况的界面 9 记录数据的情况
  • hive sql求多个字段的最小值和最大值的办法

    1 准备数据表test2 create table test2 a int b int c int d int e int 2 准备2条数据 insert into table test2 values 5 1 3 8 6 insert i
  • 软件测试策略概述

    一般来说 测试策略描述了软件开发过程中进行测试方法 用来告诉测试过程中所有可能的参与者 测试活动应该如何进行 其中主要会包括测试目标 测试新功能的方法 测试项目的时间和资源 以及测试环境等等 除此以外 测试策略应该描述测试过程中存在哪些风险
  • 前端将后端返回的文件流转成url

    将返回的流数据转换为url export function getObjectURL file type return window URL createObjectURL new Blob file type base64转url exp
  • 2020-09-27 IDEA Maven dependencyManagement中的依赖版本会覆盖传递依赖版本

    IDEA Maven dependencyManagement中的依赖版本会覆盖传递依赖版本 参考帖子 Maven传递依赖的坑 父pom中dependencyManagement版本优先级高于传递依赖版本 问题描述 同一个项目 同事拉取其他
  • 常用正则表达式

    正则表达式用于字符串处理 表单验证等场合 实用高效 现将一些常用的表达式收集于此 以备不时之需 匹配中文字符的正则表达式 u4e00 u9fa5 评注 匹配中文还真是个头疼的事 有了这个表达式就好办了 匹配双字节字符 包括汉字在内 x00
  • Python移动和嵌入式视觉应用卷积神经网络模型压缩策略

    概述 模型压缩是在计算资源有限且能耗紧张的移动设备上 有效部署神经网络模型的关键技术 传统的模型压缩技术依赖于手工制作的启发式和基于规则的策略 这需要领域专家探索在模型大小 速度和准确性之间进行权衡的大型设计空间 这通常是次优且耗时的 在本
  • dos 添加防火墙入站规则

    dos 添加防火墙入站规则 使用DOS命令如何操作Windows防火墙 命令介绍及应用举例 一 命令格式 netsh firewall 参数 命令功能 显示命令列表 add 添加防火墙配置 delete 删除防火墙配置 dump 显示一个配
  • NoClassDefFoundError之BeanCreationException异常

    前言 根据部门技术要求 同时提高系统的稳定性和易维护性 需要对现有系统进行技术升级改造 在技术改造的过程中难免会遇到一些问题 令我印象比较深刻的就是文章标题所说的BeanCreationException异常 这个看似比较常见的异常出现的原
  • function/bind的救赎(上)

    本文转自孟岩的博客 http blog csdn net myan article details 5928531 这是那篇C 0X的正文 太长 先写上半部分发了 Function bind可以是一个很简单的话题 因为它其实不过就是一个泛型