jjzjj

oop - 转到 "polymorphism"

coder 2023-06-28 原文

人们说,Go 不是一种 OO(面向对象)语言;不要在 Go 上使用 OO 术语。好的,让我描述一下我可以用 OO 做什么 --

使用 OO 语言,我可以让不同的动物根据它们的类别说不同的话:

cat.Say() // miao
sheep.Say() // bahh
cow.Say() // moo

同样是从 Shapes 获取 Area()。

然而,this go demo code让我相信这是不可能的。包括在下面的 Exhibit#1 中。

然后今天,我找到了this go demo code ,这使它完全成为可能。包括在下面的 Exhibit#2 中。

所以我的问题是,两者之间有什么根本不同,这使得第一个错误而第二个正确? 如何让第一个“起作用”?

图表#1:

// Credits: hutch
//          https://groups.google.com/d/msg/golang-nuts/N4MBApd09M8/0ij9yGHK_8EJ
////////////////////////////////////////////////////////////////////////////

/*

https://groups.google.com/d/msg/golang-nuts/N4MBApd09M8/tOO5ZXtwbhYJ

LRN:

Subtype polymorphism: Not applicable (Go doesn't have subtyping).
Although if you embed a struct A implementing interface X into a struct B,
struct B will implement interface X, and can be used instead of struct A in
places where struct A is expected. So, kind of yes.

Robert Johnstone:

interfaces behave similarly to virtual functions, but they are not identical.  See the (following) example program by hutch.

*/

package main

import "fmt"

type A struct {
    astring string
}

type B struct {
    A
    bstring string
}

type Funny interface {
    strange()
    str() string
}

func (this *A) strange() {
    fmt.Printf("my string is %q\n", this.str())
}

func (this *A) str() string {
    return this.astring
}

func (this *B) str() string {
    return this.bstring
}

func main() {
    b := new(B)
    b.A.astring = "this is an A string"
    b.bstring = "this is a B string"

    b.strange()
    // Output: my string is "this is an A string"

    // Many people familiar with OO (and unfamiliar with Go) will be quite
    // surprised at the output of that program.
}

图表#2:

// Credits: https://play.golang.org/p/Zn7TjiFQik
////////////////////////////////////////////////////////////////////////////

/*

Problem (From Polymorphism-Subtype.go):

https://groups.google.com/d/msg/golang-nuts/N4MBApd09M8/tOO5ZXtwbhYJ

LRN: Subtype polymorphism: Not applicable (Go doesn't have subtyping).

Goal:

This is to demo that "polymorphism" is still doable in Go.

*/

package main

import (
    "fmt"
)

type Shape interface {
    Area() float32
}

type Point struct {
    x float32
    y float32
}

// Make sure the structs are different sizes so we're sure it'll work with
// all sorts of types
type Circle struct {
    center Point
    radius float32
}

func (c Circle) Area() float32 {
    return 3.1415 * c.radius * c.radius
}

type Rectangle struct {
    ul Point
    lr Point
}

func (r Rectangle) Area() float32 {
    xDiff := r.lr.x - r.ul.x
    yDiff := r.ul.y - r.lr.y
    return xDiff * yDiff
}

func main() {
    mtDict := make(map[string]Shape)
    // No problem storing different custom types in the multitype dict
    mtDict["circ"] = Circle{Point{3.0, 3.0}, 2.0}
    mtDict["rect"] = Rectangle{Point{2.0, 4.0}, Point{4.0, 2.0}}

    for k, v := range mtDict {
        fmt.Printf("[%v] [%0.2f]\n", k, v.Area())
    }
}

/*

$ go run Polymorphism-Shape.go
[circ] [12.57]
[rect] [4.00]

*/

最佳答案

您的两个展品正在做不同的事情。

在第一个中,B 中嵌入了A,而B 没有实现strange() 方法本身,因此当您调用 b.strange() 时,您将获得为 A 定义的 strange() 的实现。 strange方法的接收者(this)是b.A,不是b,所以值b.A。 astring 被打印出来。如果您希望 strange 打印 bstring,则必须为 B 定义 strange

这指出了 Go 和其他 OO 语言之间的差异之一:将 A 嵌入到 B 中并不意味着 B 是一个“A 的子类”,因此不能在需要 A 类型的对象的地方使用 B 类型的对象。但是,由于 B 继承了 A 的字段和方法,因此由 A 实现的任何接口(interface)也由 B 实现>,并且,除非这些方法是专门为 B 定义的,否则它们在 B 中的 A 上运行,而不是 B 本身。

在第二个展览中,您有 Shape 接口(interface),它由 CircleRectangle 类型实现。 map 的元素类型是 Shape,因此实现该接口(interface)的任何类型都可以是 map 中的元素。当您在循环中使用接口(interface)类型的值时,您可以调用该值接口(interface)中定义的任何方法,并且将调用与该值的实际类型对应的定义。

关于oop - 转到 "polymorphism",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40195682/

有关oop - 转到 "polymorphism"的更多相关文章

  1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  3. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  4. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  5. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  6. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  7. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

  8. ruby - RVM "ERROR: Unable to checkout branch ."单用户 - 2

    我在新的Debian6VirtualBoxVM上安装RVM时遇到问题。我已经安装了所有需要的包并使用下载了安装脚本(curl-shttps://rvm.beginrescueend.com/install/rvm)>rvm,但以单个用户身份运行时bashrvm我收到以下错误消息:ERROR:Unabletocheckoutbranch.安装在这里停止,并且(据我所知)没有安装RVM的任何文件。如果我以root身份运行脚本(对于多用户安装),我会收到另一条消息:Successfullycheckedoutbranch''安装程序继续并指示成功,但未添加.rvm目录,甚至在修改我的.bas

  9. ruby - 如何关闭 ruby​​ gem "Spreadsheet?"中的文件 - 2

    下面的代码在我第一次运行它时就可以正常工作:require'rubygems'require'spreadsheet'book=Spreadsheet.open'/Users/me/myruby/Mywks.xls'sheet=book.worksheet0row=sheet.row(1)putsrow[1]book.write'/Users/me/myruby/Mywks.xls'当我再次运行它时,我会收到更多消息,例如:/Library/Ruby/Gems/1.8/gems/spreadsheet-0.6.5.9/lib/spreadsheet/excel/reader.rb:11

  10. ruby - Ruby 语法糖有 "rules"吗? - 2

    我正在学习Ruby的基础知识(刚刚开始),我遇到了Hash.[]method.它被引入a=["foo",1,"bar",2]=>["foo",1,"bar",2]Hash[*a]=>{"foo"=>1,"bar"=>2}稍加思索,我发现Hash[*a]等同于Hash.[](*a)或Hash.[]*一个。我的问题是为什么会这样。是什么让您将*a放在方括号内,是否有某种规则可以在何时何地使用“it”?编辑:我的措辞似乎造成了一些困惑。我不是在问数组扩展。我明白了。我的问题基本上是:如果[]是方法名称,为什么可以将参数放在括号内?这看起来几乎——但不完全是——就像说如果你有一个方法Foo.d

随机推荐