- 浏览: 5179091 次
- 性别:
- 来自: 天津
-
博客专栏
-
-
实战 Groovy
浏览量:29480
文章分类
- 全部博客 (639)
- 代码之谜 (6)
- JavaScript quirks (5)
- 程序员 (92)
- Java (93)
- BT编程 (7)
- html/css (64)
- Groovy&Grails (42)
- Android (20)
- C/C++ (5)
- PHP/Perl/Python (46)
- 经典文章 (51)
- CodeIgniter (14)
- JQuery (10)
- 笑话 (4)
- 其他 (32)
- javascript (69)
- 云计算 (0)
- html5 (7)
- 面试 (8)
- google (3)
- nosql (2)
- nodejs (11)
- go (5)
- erlang (1)
- 小常识 (3)
- 冷知识 (5)
- database (4)
- web (12)
- 架构 (12)
- Exception (0)
最新评论
-
jqw1992:
https://www.chromefor.com/libra ...
[福利] 开发者必备的 Chrome 插件——ChromeSnifferPlus -
litjerk:
初步算了一下,目前最最精简的Win98版是5M,他5个小时多敲 ...
让人目瞪口呆的三位世界级电脑大师 -
379855529:
。。似乎重点没说NIO啊,前面基础只是铺垫的很好的,可是我要的 ...
Java NIO与IO的详细区别(通俗篇) -
springmvc_springjpa:
spring mvc demo教程源代码下载,地址:http: ...
一步步开发 Spring MVC 应用 -
匡建武:
Good
四个程序员的一天
在 Groovy 中处处都是闭包,Groovy 闭包惟一的问题是:当每天都使用它们的时候,看起来就有点平淡了。在本文中,客座作者 Ken Barclay 和 John Savage 介绍了如何对标准的闭包(例如闭包复合和 Visitor 设计模式)进行 curry 处理。curry()
方法是由 Haskell Curry 发明的,在 JSR 标准发布之前就已经在 Groovy 语言中了。
几乎从一年前实战 Groovy 系列开始,我就已经提供了多个让您了解闭包的机会。在首次作为 alt.lang.jre 系列的一部分写 Groovy 时(“感受 Groovy”,2004 年 8 月),我介绍了 Groovy 的闭包语法,而且 就在上一期文章中,我介绍了最新的 JSR 标准对相同语法的更新。学习至今,您知道了 Groovy 闭包是代码块,可以被引用、带参数、作为方法参数传递、作为返回值从方法调用返回。而且,它们也可以作为其他闭包的参数或返回值。因为闭包是 Closure
类型的对象,所以它们也可以作为类的属性或集合的成员。
虽然这些技术都是很神奇的,但是本期文章要学习的闭包技术要比您迄今为止尝试过的都要更火辣一些。客座作者 John Savage 和 Ken Barclay 已经用 Groovy 闭包中的 curry()
方法做了一些有趣的实验,我们非常有幸可以见识他们的技艺。
![]() |
Barclay 和 Savage 的 curry 过的闭包不仅会重新激起您对熟悉的操作(例如复合)和 Visitor 设计模式的兴奋,还会用 Groovy 打开函数式编程的大门。
curry 过的函数 一般可在函数式编程语言(例如 ML 和 Haskell)中找得到(请参阅 参考资料)。curry 这个术语来自 Haskell Curry,这个数学家发明了局部函数的概念。Currying 指的是把多个参数放进一个接受许多参数的函数,形成一个新的函数接受余下的参数,并返回结果。令人兴奋的消息是,Groovy 的当前版本(在编写本文时是 jsr-02 版)支持在闭包
上使用 curry()
方法 —— 这意味着,我们这些 Groovy 星球的公民,现在可以利用函数式编程的某些方面了!
您以前可能从未用过 curry()
,所以我们先从一个简单的、熟悉的基础开始。清单 1 显示了一个叫做 multiply
的闭包。它有形式参数 x
和 y
,并返回这两个值的乘积。假设没有歧义存在,然后代码演示了用于执行 multiply
闭包的两种方法:显式(通过 call
的方式)或隐式。后一种样式引起了函数调用方式。
def multiply = { x, y -> return x * y } // closure def p = multiply.call(3, 4) // explicit call def q = multiply(4, 5) // implicit call println "p: ${p}" // p is 12 println "q: ${q}" // q is 20 |
这个闭包当然很好,但是我们要对它进行 curry 处理。在调用 curry()
方法时,不需要提供所有的实际参数。curry 过的 调用只引起了闭包的部分应用程序。闭包的 部分应用程序 是另一个 Closure
对象,在这个对象中有些值已经被修正。
清单 2 演示了对 multiply
闭包进行 curry 处理的过程。在第一个例子中,参数 x
的值被设置为 3。名为 triple
的闭包现在有效地拥有了 triple = { y -> return 3 * y }
的定义。
def multiply = { x, y -> return x * y } // closure def triple = multiply.curry(3) // triple = { y -> return 3 * y } def quadruple = multiply.curry(4) // quadruple = { y -> return 4 * y } def p = triple.call(4) // explicit call def q = quadruple(5) // implicit call println "p: ${p}" // p is 12 println "q: ${q}" // q is 20 |
可以看到,参数 x
已经从 multiply
的定义中删除,所有它出现的地方都被 3 这个值代替了。
从基本数学可能知道,乘法运算符是可交换的(换句话说 x * y = y * x
)。但是,减法运算符是不可交换的;所以,需要两个操作来处理减数和被减数。清单 3 为这个目的定义了闭包 lSubtract
和rSubtract
(分别在左边和右边),结果显示了 curry
函数的一个有趣的应用。
def lSubtract = { x, y -> return x - y } def rSubtract = { y, x -> return x - y } def dec = rSubtract.curry(1) // dec = { x -> return x - 1 } def cent = lSubtract.curry(100) // cent = { y -> return 100 - y } def p = dec.call(5) // explicit call def q = cent(25) // implicit call println "p: ${p}" // p is 4 println "q: ${q}" // q is 75 |
您会回忆起这个系列以前的文章中,闭包一般用于在 List
和 Map
集合上应用的迭代器方法 上。例如,迭代器方法 collect
把闭包应用到集合中的每个元素上,并返回一个带有新值的新集合。清单 4 演示了把 collect
方法应用于 List
和 Map
。名为 ages
的 List
被发送给 collect()
方法,使用单个闭包 { element -> return element + 1 }
作为参数。注意方法的最后一个参数是个闭包,在这个地方 Groovy 允许把它从实际参数列表中删除,并把它直接放在结束括号后面。在没有实际参数时,可以省略括号。用名为 accounts
的 Map
对象调用的 collect()
方法可以展示这一点。
def ages = [20, 30, 40] def accounts = ['ABC123' : 200, 'DEF456' : 300, 'GHI789' : 400] def ages1 = ages.collect({ element -> return element + 1 }) def accounts1 = accounts.collect { entry -> entry.value += 10; return entry } println "ages1: ${ages1}" // ages1: [21, 31, 41] println "accounts1: ${accounts1}" // accounts1: [ABC123=210, GHI789=410, DEF456=310] def ages2 = ages.collect { element -> return dec(element) } println "ages2: ${ages2}" // ages2: [19, 29, 39] |
最后一个例子搜集名为 ages
的 List
中的所有元素,并将 dec
闭包 (来自清单 3)应用于这些元素。
闭包更重要的一个特征可能就是复合(composition),在复合中可以定义一个闭包,它的目的是组合其他闭包。使用复合,两个或多个简单的闭包可以组合起来构成一个更复杂的闭包。
清单 5 介绍了一个漂亮的 composition
闭包。现在请注意仔细阅读:参数 f
和 g
代表 单个参数闭包。到现在还不错?现在,对于某些参数值 x
,闭包 g
被应用于 x,而闭包 f
被应用于生成的结果!哦,只对前两个闭包参数进行了 curry 处理,就有效地形成了一个组合了这两个闭包的效果的新闭包。
清单 5 组合了闭包 triple
和 quadruple
,形成闭包 twelveTimes
。当把这个闭包应用于实际参数 3 时,返回值是 36。
def multiply = { x, y -> return x * y } // closure def triple = multiply.curry(3) // triple = { y -> return 3 * y } def quadruple = multiply.curry(4) // quadruple = { y -> return 4 * y } def composition = { f, g, x -> return f(g(x)) } def twelveTimes = composition.curry(triple, quadruple) def threeDozen = twelveTimes(3) println "threeDozen: ${threeDozen}" // threeDozen: 36 |
非常漂亮,是么?
现在我们来研究闭包的一些更刺激的方面。我们先从一个机制开始,用这个机制可以表示包含计算模式 的闭包,计算模式是一个来自函数式编程的概念。计算模式的一个例子就是用某种方式把 List
中的每个元素进行转换。因为这些模式发生得如此频繁,所以我们开发了一个叫做 Functor
的类,把它们封装成 static Closure
。清单 6 显示了一个摘要。
package fp abstract class Functor { // arithmetic (binary, left commute and right commute) public static Closure bMultiply = { x, y -> return x * y } public static Closure rMultiply = { y, x -> return x * y } public static Closure lMultiply = { x, y -> return x * y } // ... // composition public static Closure composition = { f, g, x -> return f(g(x)) } // lists public static Closure map = { action, list -> return list.collect(action) } public static Closure apply = { action, list -> list.each(action) } public static Closure forAll = { predicate, list -> for(element in list) { if(predicate(element) == false) { return false } } return true } // ... } |
在这里可以看到名为 map
的闭包,不要把它与 Map
接口混淆。map
闭包有一个参数 f
代表闭包,还有一个参数 list
代表(不要惊讶)List
。它返回一个新 List
,其中 f
已经映射到 list
中的每个元素。当然,Groovy 已经有了用于 Lists
的 collect()
方法,所以我们在我们的实现中也使用了它。
在清单 7 中,我们把事情又向前进行了一步,对 map
闭包进行了 curry 处理,形成一个块,会将指定列表中的所有元素都乘以 12。
import fp.* def twelveTimes = { x -> return 12 * x } def twelveTimesAll = Functor.map.curry(twelveTimes) def table = twelveTimesAll([1, 2, 3, 4]) println "table: ${table}" // table: [12, 24, 36, 48] |
现在,这 就是我们称之为五星计算的东西!
关于闭包的技艺的讨论很不错,但是更关注业务的人会更欣赏下面这个例子。在考虑计算特定 Book
条目净值的问题时,请考虑商店的折扣和政府的税金(例如 增值税)。如果想把这个逻辑作为 Book
类的一部分包含进来,那么形成的解决方案可能是个难缠的方案。因为书店可能会改变折扣,或者折扣只适用于选定的存货,所以这样一个解决方案可能会太刚性了。
但是猜猜情况如何。变化的业务规则非常适合于使用 curry 过的闭包。可以用一组简单的闭包来表示单独的业务规则,然后用复合把它们以不同的方式组合起来。最后,可以用 计算模式 把它们映射到集合。
清单 8 演示了书店的例子。闭包 rMultiply
是个局部应用程序,通过使用一个不变的第二操作数,把二元乘法改变成一元闭包。两个图书闭包 calcDiscountedPrice
和 calcTax
是 rMultiply
闭包的实例,为乘数值设置了值。闭包 calcNetPrice
是计算净价的算法:先计算折扣价格,然后在折扣价格上计算销售税。最后, calcNetPrice
被应用于图书价格。
import fp.* class Book { @Property name @Property author @Property price @Property category } def bk = new Book(name : 'Groovy', author : 'KenB', price : 25, category : 'CompSci') // constants def discountRate = 0.1 def taxRate = 0.17 // book closures def calcDiscountedPrice = Functor.rMultiply.curry(1 - discountRate) def calcTax = Functor.rMultiply.curry(1 + taxRate) def calcNetPrice = Functor.composition.curry(calcTax, calcDiscountedPrice) // now calculate net prices def netPrice = calcNetPrice(bk.price) println "netPrice: ${netPrice}" // netPrice: 26.325 |
已经看到了如何把 curry 过的闭包应用于函数模式,所以现在我们来看看在使用相似的技术重新访问重要的面向对象设计模式时发生了什么。对于面向对象系统来说,必须遍历对象集合并在集合中的每个元素上执行某个操作,是非常普通的使用情况。假设一个不同的场景,系统要遍历相同的集合,但是要执行不同的操作。通常,需要用 Visitor 设计模式(请参阅 参考资料)来满足这一需求。Visitor
接口引入了处理集合元素的动作协议。具体的子类定义需要的不同行为。方法被引进来遍历集合并对每个元素应用 Visitor
动作。
如果到现在您还没猜出来,那么可以用闭包实现同的效果。这种方法的一个抽象是:使用闭包,不需要开发访问者类的层次结构。而且,可以有效地使用闭包复合和映射来定义集合的动作和效果遍历。
例如,考虑用来表示图书馆库存的类 Library
和类 Book
之间的一对多关系。可以用 List
或 Map
实现这个关系;但是 Map
提供的优势是它能提供快速的查询,也就是说用图书目录编号作为键。
清单 9 显示了一个使用 Map
的简单的一对多关系。请注意 Library
类中的两个显示方法。引入访问者时,两者都是重构的目标。
class Book { @Property title @Property author @Property catalogNumber @Property onLoan = false String toString() { return "Title: ${title}; author: ${author}" } } class Library { @Property name @Property stock = [ : ] def addBook(title, author, catalogNumber) { def bk = new Book(title : title, author : author, catalogNumber : catalogNumber) stock[catalogNumber] = bk } def lendBook(catalogNumber) { stock[catalogNumber].onLoan = true } def displayBooksOnLoan() { println "Library: ${name}" println "Books on loan" stock.each { entry -> if(entry.value.onLoan == true) println entry.value } } def displayBooksAvailableForLoan() { println "Library: ${name}" println "Books available for loan" stock.each { entry -> if(entry.value.onLoan == false) println entry.value } } } def lib = new Library(name : 'Napier') lib.addBook('Groovy', 'KenB', 'CS123') lib.addBook('Java', 'JohnS', 'CS456') lib.addBook('UML', 'Ken and John', 'CS789') lib.lendBook('CS123') lib.displayBooksOnLoan() // Title: Groovy; author: KenB lib.displayBooksAvailableForLoan() // Title: UML; author: Ken and John // Title: Java; author: JohnS |
清单 10 包含 Library
类中的几个闭包,模拟了访问者的用法。action
闭包(与 map
闭包有点相似)把 action
闭包应用于 List
的每个元素。如果某本书被借出,则闭包 displayLoanedBook
显示它;如果某本书未被借出,则闭包 displayAvailableBook
显示它。两者都扮演访问者和相关的动作。用 displayLoanedBook
对 apply
闭包进行 curry 处理,会形成闭包 displayLoanedBooks
,它为处理图书集合做好了准备。类似的方案也用来生成可供借阅的图书显示,如清单 10 所示。
import fp.* class Book { @Property title @Property author @Property catalogNumber @Property onLoan = false String toString() { return " Title: ${title}; author: ${author}" } } class Library { @Property name @Property stock = [ : ] def addBook(title, author, catalogNumber) { def bk = new Book(title : title, author : author, catalogNumber : catalogNumber) stock[catalogNumber] = bk } def lendBook(catalogNumber) { stock[catalogNumber].onLoan = true } def displayBooksOnLoan() { println "Library: ${name}" println "Books on loan" displayLoanedBooks(stock.values()) } def displayBooksAvailableForLoan() { println "Library: ${name}" println "Books available for loan" displayAvailableBooks(stock.values()) } private displayLoanedBook = { bk -> if(bk.onLoan == true) println bk } private displayAvailableBook = { bk -> if(bk.onLoan == false) println bk } private displayLoanedBooks = Functor.apply.curry(displayLoanedBook) private displayAvailableBooks = Functor.apply.curry(displayAvailableBook) } def lib = new Library(name : 'Napier') lib.addBook('Groovy', 'KenB', 'CS123') lib.addBook('Java', 'JohnS', 'CS456') lib.addBook('UML', 'Ken and John', 'CS789') lib.lendBook('CS123') lib.displayBooksOnLoan() // Title: Groovy; author: KenB lib.displayBooksAvailableForLoan() // Title: UML; author: Ken and John // Title: Java; author: JohnS |
在结束之前,我们来看一下 Groovy 闭包的一个附加用途。请考虑一个被建模为具有许多 Employee
的 Company
的应用程序。递归的关系在单个 Employee
(团队领导)和许多 Employee
(团队成员)之间进一步建立起一对多的聚合。图 1 是这样一个组织的类图。
可以用闭包来表述模型架构上的完整性。例如,在这个例子中,可能想确保每个员工都分配了一个经理。简单的闭包 hasManager
为每个员工表达了这个需求: def hasManager = { employee -> return (employee.manager != null) }
。
来自清单 6 的 Functor
类中的 forAll
闭包的局部应用程序能够描述架构的需求:def everyEmployeeHasManager = Functor.forAll.curry(hasManager)
。
清单 11 演示了 curry 过的闭包的应用:测试系统架构的完整性。
import fp.* /** * A company with any number of employees. * Each employee is responsible * to a team leader who, in turn, manages a team of staff. */ import java.util.* class Employee { @Property id @Property name @Property staff = [ : ] @Property manager = null String toString() { return "Employee: ${id} ${name}" } def addToTeam(employee) { staff[employee.id] = employee employee.manager = this } } class Company { @Property name @Property employees = [ : ] def hireEmployee(employee) { employees[employee.id] = employee } def displayStaff() { println "Company: ${name}" println "====================" employees.each { entry -> println " ${entry.value}" } } } def co = new Company(name : 'Napier') def emp1 = new Employee(id : 123, name : 'KenB') def emp2 = new Employee(id : 456, name : 'JohnS') def emp3 = new Employee(id : 789, name : 'JonK') co.hireEmployee(emp1) co.hireEmployee(emp2) co.hireEmployee(emp3) emp3.addToTeam(emp1) emp3.addToTeam(emp2) co.displayStaff() // Architectural closures def hasManager = { employee -> return (employee.manager != null) } def everyEmployeeHasManager = Functor.forAll.curry(hasManager) def staff = new ArrayList(co.employees.values()) println "Every employee has a manager?: ${everyEmployeeHasManager.call(staff)}" // false |
在本文中您已看到了大量闭包,但是希望能激起您对更多闭包的渴望。在学习乘法例子时,curry 过的闭包使得实现计算的函数模式出奇得容易。一旦掌握了这些模式,就可以把它们部署到常见的企业场景中,例如我们在书店例子中把它们应用于业务规则。把闭包应用于函数模式是令人兴奋的,一旦这么做了之后,再把它们应用于面向对象设计模式,就不是什么大事情了。Curry 过的闭包可以用来模拟 Visitor 模式的基本元素,正如在 Library
例子中显示的。它们在软件测试期间执行完整性测试时也会有用,就像用 Company
例子所展示的。
本文中看到的全部例子都是企业系统常见的用例。看到 Groovy 闭包和 curry
方法能够如此流畅地应用于众多编程场景、函数模式和面向对象模式,真是激动人心。Haskell Curry 肯定发现了这个可怕的groovy!
发表评论
-
实战 Groovy: 用 Groovy 打造服务器端
2010-07-10 11:07 2742Groovlet 和 GroovyServer P ... -
实战 Groovy: 用 Groovy 生成器作标记
2010-07-10 11:07 2085Groovy 生成器让您能够利用诸如 Swing 这样 ... -
实战 Groovy: for each 剖析
2010-07-10 11:07 18224在这一期的 实战 Groovy 中,Scott Davi ... -
实战 Groovy: 用 Groovy 进行 Ant 脚本编程
2010-07-10 11:07 2076Ant 和 Maven 两者在构建处理工具的世界中占统 ... -
实战 Groovy: 在 Java 应用程序中加一些 Groovy 进来
2010-07-10 11:06 4353您有没有想过在自己相对复杂的 Java 程序中嵌入 G ... -
实战 Groovy: Groovy 的腾飞
2010-07-10 11:06 2208随着 Groovy JSR-1(及其后续发行版本)的发 ... -
实战 Groovy: 关于 MOP 和迷你语言
2010-07-10 11:06 2085将耳朵贴到地上仔细听 —— MOP 正在前进!了解一下 ... -
实战 Groovy: 用 Groovy 更迅速地对 Java 代码进行单元测试
2010-07-10 11:06 2312不久以前,developerWor ... -
实战 Groovy: 构建和解析 XML
2010-07-10 11:05 7164通过本文,您将了解 ... -
实战 Groovy: 用 Groovy 进行 JDBC 编程
2010-07-10 11:05 5211这个月,随着 Andrew G ... -
实战 Groovy: 美妙的操作符
2010-07-10 11:05 2299Java™ 取消了操作符重载,但是新兴的 Groovy ... -
实战 Groovy: 使用 Groovy 模板进行 MVC 编程
2010-07-10 11:04 2942视图是 MVC 编程的一个重要部分,而 MVC 编程本 ... -
实战 Groovy: 用 Groovy 减少代码冗余
2010-07-10 11:04 2075Groovy 简洁的语法将 ... -
实战 Groovy: Groovy:Java 程序员的 DSL
2010-07-10 11:04 3089Groovy 专家 Scott Davis 将重新开始 ... -
精通 Grails: 构建您的第一个 Grails 应用程序
2010-07-06 09:37 1659Java™ 程序员不需要 ... -
Grails 部署
2010-07-06 09:36 6089部署 Grails可以使用很多种方式来部署,每一种 ... -
Grails 脚手架
2010-07-05 08:20 4089脚手架 根据指定的领域类,脚手架为你自动生成 ... -
Grails Grails 与 Hibernate
2010-07-05 08:19 2710Grails 与 Hibernate 如果 GOR ... -
Grails Grails和 Spring
2010-07-05 08:19 7937Grails和 Spring 这一节适合于高级用户 ... -
Grails Web服务
2010-07-05 08:19 3971Web服务 Web服务就是让你的web应用提供一套 ...
相关推荐
vue3 访问通义千问聊天代码例子
基于Python的Flask-vue基于Hadoop的智慧校园数据共享平台实现源码-演示视频 项目关键技术 开发工具:Pycharm 编程语言: python 数据库: MySQL5.7+ 后端技术:Flask 前端技术:HTML 关键技术:HTML、MYSQL、Python 数据库工具:Navicat、SQLyog
【实验1】:读取一次AI0通道数值 【实验2】:一次读取AI0通道多个数值 【实验3】:单次模拟量输出 【实验4】:连续模拟量输出(输出一个正弦曲线)
无人船的Smith-PID跟踪控制方法研究及实现:融合传统与最优PID策略的LOS曲线跟踪资料,基于无人船Smith-PID改进跟踪控制技术及其LOS曲线跟踪方法研究资料,基于无人船的smith-pid跟踪控制资料。 首先,针对pid进行了改进,有传统pid,最优pid和基于smith的pid三种控制方式。 然后还在smithpid基础上设计了LOS的曲线跟踪方法。 (有对应参考文献)。 有意者可直接联系,参考学习资料。 python语言。 ,基于无人船的Smith-PID跟踪控制; PID改进(传统PID、最优PID、基于Smith的PID); Smith-PID曲线跟踪方法; 参考学习资料; Python语言。,基于无人船的Smith-PID优化跟踪控制资料
自研船舶电力推进系统MATLAB仿真报告:从柴油机+同步发电机到异步电机直接转矩控制的全面模拟与实践,《船舶电力推进系统自搭MATLAB仿真报告:从柴油机同步发电机到异步电机直接转矩控制的完整过程与参数配置详解》,自己搭建的船舶电力推进系统(船舶电力推进自动控制)完全自搭MATLAB仿真,可适度,含对应27页正文的中文报告,稀缺资源,仿真包括船舶电站,变流系统和异步电机直接转矩控制,放心用吧。 三个文件逐层递进 柴油机+同步发电机(船舶电站) 柴油机+同步发电机+不控整流全桥逆变 柴油机+同步发电机+变流模块+异步电机直接转矩控制 所有参数都是配好的,最大负载参考变流系统所带负载两倍,再大柴油机和同步发电机参数就不匹配了,有能力可以自己调 ,核心关键词:船舶电力推进系统; MATLAB仿真; 船舶电站; 变流系统; 异步电机直接转矩控制; 柴油机; 同步发电机; 不控整流全桥逆变; 参数配比。,《船舶电力推进系统MATLAB仿真报告》
西门子博图WinCC V15自动化系统项目实战:多服务器客户端下的PID DCS闭环控制及参数调整实战指南,西门子博图WinCC V15自动化系统项目实战:多服务器客户端下的PID DCS闭环控制及参数调整实战指南,西门子博图WinCC V 15大型自动化系统项目,包含多台服务器客户端项目,系统采用安全1516F -3PN DP 外挂多台精智面板,1200PLC ET200SP 变频器 对整个工艺过程PID DCS 闭环过程控制,如何调整温度压力流量液位等参数,实用工程项目案例 ,西门子博图WinCC V 15; 大型自动化系统; 多台服务器客户端; 安全外挂; 精智面板; 1200PLC ET200SP; 变频器; PID DCS; 闭环过程控制; 温度压力流量液位调整; 工程项目案例,西门子博图WinCC V15大型项目:多服务器客户端的PID DCS闭环控制与实用参数调整
内容概要:本文详尽介绍了计算机网络相关资源及其各方面构成要素,首先阐述了硬件层面的各种传输媒介和设备如双绞线、同轴电缆、光纤以及台式电脑、笔记本、大型计算机等设备,还包括网络互联所需的各类组件如网卡、交换机、路由器等。其次探讨了多种操作系统的特性和主要功能,以及各类通讯和支持应用程序的概述,涵盖浏览器、图像和视频编辑等常用软件。再深入讨论了多种常见网络协议如TCP、UDP、HTTP等的功能特性。最后还提到了确保网络安全运行的重要措施和工具如MIB、SNMP以及防火墙、入侵检测系统等。并且简要提到计算机网络在不同的应用环境,从局域网到移动网络。 适合人群:所有对计算机网络技术感兴趣的初学者和希望深入了解各个组成成分的技术人员. 使用场景及目标:为用户提供计算机网络资源全面而系统的认识,帮助他们建立对于该领域的理论和技术的扎实认知基础,提高在实际环境中识别配置及维护计算机网络系统的能力.
海神之光上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作
ABAQUS中隧道结构模型的无限元应用:超声激励源的施加方法、3D无限元吸收边界的添加技巧、模型结果精确性校核流程及教学视频与CAE、INP文件解析,ABAQUS隧道模型中3D无限元吸收边界的应用:超声激励源的施加与模型结果精确性校核的实践教程,ABAQUS无限元吸收边界,abaqus隧道无限元,1.超声激励源施加;2.3D无限元吸收边界添加方法;3.模型结果精确性校核;4.提供教学视频,cae、inp文件。 ,ABAQUS无限元吸收边界;ABAQUS隧道无限元;超声激励源施加;3D无限元吸收边界添加;模型结果精确性校核;CAE和INP文件。,ABAQUS中超声激励下无限元吸收边界设置及模型精度验证教程
海神之光上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作
git自用lllllllllllllllllll
本资源与文章【Django小白项目】为一体,此为已成功项目,供给给Django初学者做参考,有不会的问题可以私信我噢~
使用一维数据表示向量和二维矩阵,支持常用运算。
1、以上文章可用于参考,请勿直接抄袭,学习、当作参考文献可以,主张借鉴学习 2、资源本身不含 对应项目代码,如需完整项目源码,请私信博主获取
基于多目标粒子群优化算法(MOPSO)的微电网多目标经济运行分析与优化策略考虑响应侧响应的协同调度策略,基于多目标粒子群优化算法(MOPSO)的微电网经济调度优化:含风光储荷一体化模型与需求侧响应策略,考虑需求侧响应的微电网多目标经济运行 建立了含风光储荷的微电网模型,以发电侧成本(包括风光储以及电网的购电成本)和负荷侧成本最小为目标,考虑功率平衡以及储能SOC约束,建立了多目标优化模型,通过分时电价引导负荷需求侧响应,得到可削减负荷量,同时求解模型,得到风光储以及电网的运行计划。 这段代码是一个使用多目标粒子群优化算法(MOPSO)解决问题的程序。下面我将对程序进行详细的分析和解释。 首先,程序的目标是通过优化算法来解决一个多目标优化问题。程序中使用的优化算法是多目标粒子群优化算法(MOPSO),该算法通过迭代更新粒子的位置和速度来搜索最优解。 程序的主要功能是对能源系统进行优化调度,包括光伏发电、风力发电、储能和电网供电。程序的目标是最小化能源系统的成本,并满足负荷需求。 程序的主要思路是使用粒子群优化算法来搜索最优解。程序中定义了一个粒子类(Particle),每个粒子代
data.gov.sg geojson部分项目整理
基于MATLAB Simulink的避障功能欠驱动无人船航迹跟踪控制仿真实验研究,基于MATLAB Simulink的欠驱动无人船避障功能路径跟踪控制仿真实验研究,包含避障功能的欠驱动无人船航迹(路径)跟踪控制仿真实验,基于MATLAB Simulink制作 ,避障功能; 欠驱动无人船; 航迹(路径)跟踪控制; MATLAB Simulink 仿真实验; 避障算法。,基于MATLAB Simulink的避障无人船航迹跟踪控制仿真实验
海神之光上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作