Julia: 多种类型使用相同函数?

5
我有一个定义在向量上的大函数,但我希望它也能适用于单个值。我希望第一个参数的类型可以是向量或数字。
我尝试了以下方法:
function bigfunction(x::Vector, y::Float64=0.5)

  # lots of stuff
  z = x .+ y
  return z
end


bigfunction(x::Number) = bigfunction()

该函数适用于向量,但不适用于数字。
bigfunction([0, 1, 3])
bigfunction(2)

我有时会看到Union{},我需要做些什么呢?还是以不同的方式重新定义该方法?


3
union{}是解决你的问题的完美选择:function bigfunction(x::Union{Vector,Number}, y::Float64=0.5)可以实现你想要的功能。 - Picaud Vincent
它完美地工作了,非常感谢! - Dominique Makowski
7
或者将最后一行改为 bigfunction(x::Number) = bigfunction([x])。这种风格可能更加简洁。 - Robert Hönig
2
我赞成Robert的做法。一些操作在向量和数字上的处理方式有很大的不同,尽管现在可能可以正常工作,但对于将来的bigfunction进行小改变,如果作者没有仔细确保每一行都与向量或数字输入兼容,很容易就会出问题。Robert的方法非常巧妙地避开了这个问题(我在我的代码中经常使用类似的习惯用语)。 - Colin T Bowers
你真的需要将y限制为Float64吗?现在,如果y是整数、复数、单精度浮点数等,该函数将无法工作。考虑使用y::Numbery::Real。我不知道bigfunction应该做什么,但请考虑是否可以为(x::Number, y::Number=0.5)定义它,然后在x是数组时使用广播,也就是说,当x是数组时调用bigfunction.(x, y)(带有一个点)。 - DNF
@DominiqueMakowski 这对于像我这样初次接触Julia的人来说是一个很好的问题。 - Julia Learner
2个回答

4

这个问题和回答帮我理解了Chris Rackauckas在Julia中类型分发的重要性所述的一些观点,他在伟大的博客文章中详细阐述了该主题。

我将回答整理成以下代码:

# I ran this only in Julia 1.0.0.

## ========== Original function ==========
## function bigfunction(x::Vector, y::Float64=0.5)
##     # lots of stuff
##     z = x .+ y
##     return z
## end
## bigfunction(x::Number) = bigfunction()
## println(bigfunction([0, 1, 3]))
## println(bigfunction(2))
## ---------- Output has ERROR ----------
## [0.5, 1.5, 3.5]
## ERROR: LoadError: MethodError: no method matching bigfunction()


# ========== Answer Suggested by Picaud Vincent in comments ==========
# Note use of Union in function signature.
function bigfunction(x::Union{Vector, Number}, y::Float64=0.5)
    # lots of stuff
    z = x .+ y
    return z
end
println(bigfunction([0, 1, 3]))
println(bigfunction(2))
## ---------- Output Okay ----------
## [0.5, 1.5, 3.5]
## 2.5


# ========== Answer Suggested by Robert Hönig in comments ==========
# Note change in line right after function definition.
function bigfunction(x::Vector, y::Float64=0.5)
    # lots of stuff
    z = x .+ y
    return z
end
bigfunction(x::Number) = bigfunction([x])
println(bigfunction([0, 1, 3]))
println(bigfunction(2))
## ---------- Output Okay ----------
## [0.5, 1.5, 3.5]
## 2.5


# ========== Answer Suggested by Chris Rackauckas ==========
# Note change in function signature using duct typing--no type for x.
function bigfunction(x, y=0.5)
    # lots of stuff
    z = x .+ y
    return z
end
println(bigfunction([0, 1, 3]))
println(bigfunction(2))
## ---------- Output Okay ----------
## [0.5, 1.5, 3.5]
## 2.5

3
或者鸭子类型。请记住,函数始终会自动专门化,因此选择有限的调度不会影响性能。
function bigfunction(x, y=0.5)

  # lots of stuff
  z = x .+ y
  return z
end

这种方法具有良好的性能,而且可以适用于更多类型。有关类型分派设计的更多信息,请参见此博客文章


很有趣,随着所有这些调度谈话的出现,我认为它确实更有效率,谢谢。 - Dominique Makowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接