struct作为函数使用

julia> struct Foo
       end

julia> f = Foo()
Foo()

julia> (x::Foo)() = println("hello")

julia> f()
hello

在别人的code里看到把结构体拿来当函数的做法。没想到julia还有这种用法。
这样设计的想法是什么?

这是 Julia 中的函子


我们把函数 f(x)f 称为“函数名变量”,x 称为函数参数变量;Julia 的多重派发不仅可以对函数参数变量进行,还可以对函数名变量进行,效果类似 Python 里的 __call__ 方法。

比如定义参数化类型 Format,用于数据类型转化

struct Format{T<:Integer} end

(func::Format{T})(a::Float64) where T = T(floor(a))

int32 = Format{Int32}()

int32(1.2) # 输出结果为 1

第二行的派发规则:如果函数 funcFormat{T} 类型,函数变量 aFloat64 类型,则取整函数 floor 作用于 a,并返回 T 类型的结果。

第三行实例化,得到类型为 Format{Int32} 的函数 int32

第四行调用 int32(1.2),得到 1

再比如一个稍复杂点的例子:

  1. 定义函数 f:判断元素 x 是否在区间 [a,b]

    f(x,a,b) = a ≤ x ≤ b # 判断 x 是否在 [a,b] 上
    a,b = 3,7
    data = rand(1:10,5)
    @show f.(data,a,b)
    

    深度截图_选择区域_20211101171439

  2. 我们希望每次输入 ab,就得到一个判断函数

    struct MinMax
        min::Int64
        max::Int64
    end
    (func::MinMax)(x)=func.min ≤ x ≤ func.max
    

    1-4 行定义结构类型
    最后一行对函数名变量派发,当左侧 func 的数据类型为 MinMax 时,执行右侧运算。

  3. 原先的调用方式 f.(data,a,b) ,现在改为

    inrange = MinMax(3,7) # 实例化
    @show inrange.(data)
    

    20211101172943

  4. 通过对“函数名变量”的派发,具体类型 MinMax 的每次实例化,都得到一个函数。

Ref: Julia 学习笔记(二) | 类型,派发与设计模式 | 学习空间

2 个赞

很多语言都有这种功能, 不光是 Julia. 这个叫 Function-like objects 或者 functor (不是函数式编程里的那个 functor).

Methods are associated with types, so it is possible to make any arbitrary Julia object “callable” by adding methods to its type. (Such “callable” objects are sometimes called “functors.”)

比如在 Python 里, 任何定义了 __call__ method 的 class 都可以当作 function 使用. 3. Data model — Python 3.12.3 documentation 从 OOP 的角度上来说, 函数 function 不过是一个 object. 没什么特殊的.

2 个赞