如何在julia中创建一个"单一调度,面向对象的类",其行为类似于具有公共/私有字段和方法的标准Java类

Tas*_*nou 14 oop single-dispatch julia

我在一本书中读到"你不能用julia创造传统'课程',采用单调度方式,比如obj.myfunc()"......我认为听起来更像是挑战而不是事实.

所以这是我的JavaClass公共/私人领域和方法的类型,仅仅是为了在朱莉娅有一些像丑陋这样丑陋的冲击和恐怖因素,在开发人员为避免它而烦恼之后:

type JavaClass

    # Public fields
    name::String

    # Public methods
    getName::Function
    setName::Function
    getX::Function
    getY::Function
    setX::Function
    setY::Function

    # Primary Constructor - "through Whom all things were made."
    function JavaClass(namearg::String, xarg::Int64, yarg::Int64)

        # Private fields - implemented as "closed" variables
        x = xarg
        y = yarg

        # Private methods used for "overloading"
        setY(yarg::Int64) = (y = yarg; return nothing)
        setY(yarg::Float64) = (y = Int64(yarg * 1000); return nothing)

        # Construct object
        this = new()
        this.name = namearg
        this.getName = () -> this.name
        this.setName = (name::String) -> (this.name = name; return nothing)
        this.getX = () -> x
        this.getY = () -> y
        this.setX = (xarg::Int64) -> (x = xarg; return nothing)
        this.setY = (yarg) -> setY(yarg) #Select appropriate overloaded method

        # Return constructed object
        return this
    end

    # a secondary (inner) constructor
    JavaClass(namearg::String) = JavaClass(namearg, 0,0)
end
Run Code Online (Sandbox Code Playgroud)

使用示例:

julia> a = JavaClass("John", 10, 20);

julia> a.name # public
"John"

julia> a.name = "Jim";

julia> a.getName()
"Jim"

julia> a.setName("Jack")

julia> a.getName()
"Jack"

julia> a.x # private, cannot access
ERROR: type JavaClass has no field x

julia> a.getX()
10

julia> a.setX(11)

julia> a.getX()
11

julia> a.setY(2) # "single-dispatch" call to Int overloaded method

julia> a.getY()
2

julia> a.setY(2.0)

julia> a.getY()  # "single-dispatch" call to Float overloaded method
2000

julia> b = JavaClass("Jill"); # secondary constructor

julia> b.getX()
0
Run Code Online (Sandbox Code Playgroud)

本质上,构造函数变成了一个闭包,即创建"私有"字段和方法/重载的方式.有什么想法吗?(除了"OMG为什么???你为什么要这样做?")
除了其他方法吗?
您可以设想任何可能导致失败的场景吗?

Jef*_*son 29

当然,这不是在朱莉娅中创建对象和方法的惯用方法,但它也没有任何可怕的错误.在任何带闭包的语言中,您都可以像这样定义自己的"对象系统",例如,查看在Scheme中开发的许多对象系统.

在julia v0.5中,由于闭包将捕获的变量自动表示为对象字段,因此有一种特别灵活的方法可以做到这一点.例如:

julia> function Person(name, age)
        getName() = name
        getAge() = age
        getOlder() = (age+=1)
        ()->(getName;getAge;getOlder)
       end
Person (generic function with 1 method)

julia> o = Person("bob", 26)
(::#3) (generic function with 1 method)

julia> o.getName()
"bob"

julia> o.getAge()
26

julia> o.getOlder()
27

julia> o.getAge()
27
Run Code Online (Sandbox Code Playgroud)

你必须返回一个函数才能做到这一点很奇怪,但确实如此.这可以从许多优化中获益,例如为您确定精确字段类型的语言,因此在某些情况下我们甚至可以内联这些"方法调用".另一个很酷的功能是功能的底线控制哪些字段是"公共的"; 那里列出的任何东西都将成为对象的一个​​领域.在这种情况下,您只获取方法,而不是名称和年龄变量.但是,如果你添加name到列表中,那么你也可以做到o.name.当然这些方法也是多方法; 您可以为其他人添加多个定义getOlder,它会像您期望的那样工作.

  • 很有意思!特别是关于捕获变量成为字段的一点!但是,我发现这种方法存在问题:这些字段似乎是不可改变的,这违背了"公共"字段的目的; 而且,如果存在"setter"方法,它们的价值似乎变成"盒装",而不仅仅是"吸气"方法,导致进一步的复杂化(例如,如果将'age`添加到上面的"公共"变量中,`o.age + 1`失败,出现`ERROR:MethodError:没有方法匹配+(:: Core.Box,:: Int64)`).用这种方法可以解决这些问题吗? (2认同)
  • 我确实喜欢这样的事实,即这可能导致潜在的"可调用"对象(即复合语句中的最后一个参数是函数本身)!它几乎就像创建一个"对象",它也有一个重载的`()`运算符,就像C++中的Functors一样. (2认同)
  • PS:见到造物主是一种荣幸.(原谅我,主啊!我不值得!) (2认同)