鸭式打字与静态打字相比有什么优势?

时间:2020-03-05 18:48:50  来源:igfitidea点击:

我正在对Groovy进行更多的研究和试验,并且试图将自己的思想围绕在Groovy中实现我在Java中无法/无法做到的事情的利弊。对我来说,动态编程仍然只是一个概念,因为我一直沉迷于静态和强类型语言。

Groovy使我可以进行鸭式操作,但是我看不到它的价值。鸭式打字比静态打字更有效率吗?我可以在代码实践中做些什么来帮助我把握它的好处?

我在考虑Groovy时问这个问题,但我知道它不一定是Groovy问题,因此我欢迎每个代码阵营的回答。

解决方案

回答

鸭式输入并不是静态输入,而是静态输入。使用静态类型时,我们始终必须担心数据是正确的类型,而在Java中,它会通过强制转换为正确的类型来显示。只要使用正确的方法,使用鸭子类型都不会影响类型,因此,它实际上消除了很多类型转换和类型转换的麻烦。

回答

在使用鸭子一段时间之前,很难看到鸭子打字的价值。习惯了它之后,我们将意识到不必处理接口或者不必担心某种东西是什么类型的负担,这将给我们带来沉重的负担。

回答

@克里斯·邦奇

并不是说静态类型比鸭子类型更有生产力,因为它只是有所不同。使用鸭子类型时,我们始终必须担心数据具有正确的方法,而在Javascript或者Ruby中,它会通过大量方法测试显示出来。使用静态类型无关紧要,只要它是正确的接口即可,因此它实际上只是消除了许多测试和类型之间转换的麻烦。

抱歉,我必须这样做...

回答

如果我们使用的Haskell具有令人难以置信的静态类型系统,则静态类型没有问题。但是,如果使用的Java和C ++这样的语言具有严重残缺的类型系统,则鸭子类型无疑是一种改进。

想象一下,尝试在Java中使用诸如"映射"之类的简单方法(不,我不是指数据结构)。即使是泛型,也很少得到支持。

回答

鸭子键入会破坏大多数现代IDE的静态检查,这会在我们键入时指出错误。有些人认为这是一个优势。我希望IDE / Compiler告诉我我已经尽了一个愚蠢的程序员技巧。

我最近最喜欢的反对鸭类打字的观点来自Grails项目DTO:

class SimpleResults {
    def results
    def total
    def categories
}

结果是类似于Map <String,List <ComplexType >>的东西,只有在不同类中跟踪方法调用的踪迹,直到找到它的创建位置,才能发现它。对于最终的好奇,totalList &lt;ComplexType>s的大小之和,categoriesMap的大小。

关于鸭类打字的许多评论并不能真正证实其主张。不"担心"某种类型对于维护或者使应用程序可扩展而言是不可持续的。我真的有很好的机会看到Grails在我上一份合同中的运作中,并且观看起来真的很有趣。每个人都为能够"创建应用程序"而获得的成就感到高兴,而不幸的是,这一切都在后端追上了我们。

回答

Groovy在我看来也是如此。当然,我们可以编写非常简洁的代码,并且在使用属性,集合等方面的工作上肯定有一些不错的方法。但是,不知道来回传递到底是什么的代价越来越糟。在某个时候,我们想知道为什么该项目要进行80%的测试和20%的工作才能抓挠脑袋。这里的教训是"较小"不会使"可读性更高"的代码成为现实。抱歉,它的简单逻辑是,我们必须凭直觉知道的越多,那么理解代码的过程就变得越复杂。这就是为什么在过去的几年中,GUI已经变得过于具有标志性,可以肯定它看上去很漂亮,但是WTH的运行并不总是那么明显。

class SimpleResults {
    def mapOfListResults
    def total
    def categories
}

该项目上的人们似乎很难"钉牢"所学到的教训,但是当我们有方法返回单个T类型的元素,一个T的数组,一个ErrorResult或者一个null时,这很明显。

Long calculateRating(A someObj, B, otherObj) {

   //some fake algorithm here:
   if(someObj.doStuff('foo') > otherObj.doStuff('bar')) return someObj.calcRating());
   else return otherObj.calcRating();

}

与Groovy一起工作对我来说是一件好事,但是可观的可计费时间却吸引了我!

public interface MyService {
    public int doStuff(String input);
}

这是鸭子输入省力的一种情况。

public long calculateRating(MyService A, MyServiceB);

这是一个非常琐碎的课程

现在进行单元测试:

由于没有静态类型检查,我们能够用Expando代替SearchEngine。使用静态类型检查,我们将不得不确保SearchEngine是一个接口,或者至少是一个抽象类,并为其创建完整的模拟实现。这是劳动密集型的,或者我们可以使用复杂的单用途模拟框架。但是鸭子的输入是通用的,对我们有帮助。

回答

由于使用鸭子类型,我们的单元测试可以提供任何旧对象来代替依赖项,只要它实现了被调用的方法即可。

要强调的是,我们可以使用静态类型的语言来做到这一点,并仔细使用接口和类层次结构。但是使用鸭子打字可以减少思考和按键操作。

那是鸭子打字的优势。这并不意味着动态类型化是在所有情况下都可以使用的正确范例。在我的Groovy项目中,当我感觉有关类型的编译器警告会有所帮助时,我想切换回Java。

我的想法:

回答

动态打字或者鸭子打字的语言是玩具。我们无法获得Intellisense,而且会浪费编译时间(或者在使用像VS这样的REAL IDE时失去编辑时间,而不是其他人认为是IDE的垃圾)代码验证。

远离所有不是静态类型的语言,其他所有东西都只是受虐狂。

{段落}

{段落}

回答

{段落}

{段落}

class BookFinder {
    def searchEngine

    def findBookByTitle(String title) {
         return searchEngine.find( [ "Title" : title ] ) 
    }
}

{段落}

void bookFinderTest() {
    // with Expando we can 'fake' any object at runtime.
    // alternatively you could write a MockSearchEngine class.
    def mockSearchEngine = new Expando()
    mockSearchEngine.find = {
        return new Book("Heart of Darkness","Joseph Conrad")
    }

    def bf = new BookFinder()
    bf.searchEngine = mockSearchEngine
    def book = bf.findBookByTitle("Heart of Darkness")
    assert(book.author == "Joseph Conrad"
}

{段落}

{段落}

{段落}

{段落}

回答

{段落}

{段落}

{段落}