方法重载 #

一、方法重载概念 #

1.1 什么是方法重载 #

为已存在的函数添加新方法,使其支持新的类型:

julia
struct Point
    x::Float64
    y::Float64
end

Base.:+(p1::Point, p2::Point) = Point(p1.x + p2.x, p1.y + p2.y)

Point(1.0, 2.0) + Point(3.0, 4.0)

1.2 扩展标准库函数 #

julia
import Base: show, length

struct MyVector
    data::Vector{Int}
end

length(v::MyVector) = length(v.data)

show(io::IO, v::MyVector) = print(io, "MyVector($(v.data))")

v = MyVector([1, 2, 3])
length(v)

二、运算符重载 #

2.1 算术运算符 #

julia
import Base: +, -, *, /

struct Point
    x::Float64
    y::Float64
end

+(p1::Point, p2::Point) = Point(p1.x + p2.x, p1.y + p2.y)
-(p1::Point, p2::Point) = Point(p1.x - p2.x, p1.y - p2.y)
*(p::Point, s::Real) = Point(p.x * s, p.y * s)
*(s::Real, p::Point) = Point(p.x * s, p.y * s)
/(p::Point, s::Real) = Point(p.x / s, p.y / s)

Point(1.0, 2.0) + Point(3.0, 4.0)
Point(1.0, 2.0) * 2
2 * Point(1.0, 2.0)

2.2 比较运算符 #

julia
import Base: ==, <, isless

struct Person
    name::String
    age::Int
end

==(p1::Person, p2::Person) = p1.name == p2.name && p1.age == p2.age
<(p1::Person, p2::Person) = p1.age < p2.age
isless(p1::Person, p2::Person) = p1.age < p2.age

Person("Alice", 25) == Person("Alice", 25)
Person("Alice", 25) < Person("Bob", 30)

2.3 索引运算符 #

julia
import Base: getindex, setindex!, length

struct MyArray
    data::Vector{Int}
end

getindex(arr::MyArray, i::Int) = arr.data[i]
setindex!(arr::MyArray, val, i::Int) = (arr.data[i] = val)
length(arr::MyArray) = length(arr.data)

arr = MyArray([1, 2, 3, 4, 5])
arr[1]
arr[1] = 10
length(arr)

三、常用重载函数 #

3.1 show #

自定义显示格式:

julia
import Base: show

struct Point
    x::Float64
    y::Float64
end

show(io::IO, p::Point) = print(io, "Point($(p.x), $(p.y))")
show(io::IO, ::MIME"text/plain", p::Point) = print(io, "Point with coordinates ($(p.x), $(p.y))")

Point(1.0, 2.0)

3.2 convert #

类型转换:

julia
import Base: convert

struct MyInt
    value::Int
end

convert(::Type{Int}, x::MyInt) = x.value
convert(::Type{MyInt}, x::Int) = MyInt(x)

Int(MyInt(10))
MyInt(10)

3.3 promote #

类型提升:

julia
import Base: promote_rule

struct MyFloat
    value::Float64
end

promote_rule(::Type{MyFloat}, ::Type{Int}) = MyFloat

promote(MyFloat(1.0), 2)

3.4 iterate #

迭代支持:

julia
import Base: iterate, length

struct Countdown
    start::Int
end

iterate(c::Countdown) = c.start > 0 ? (c.start, c.start - 1) : nothing
iterate(c::Countdown, state) = state > 0 ? (state, state - 1) : nothing
length(c::Countdown) = c.start

for i in Countdown(5)
    println(i)
end

四、实践练习 #

4.1 练习1:复数类型 #

julia
import Base: +, -, *, /, abs, show

struct MyComplex
    real::Float64
    imag::Float64
end

+(a::MyComplex, b::MyComplex) = MyComplex(a.real + b.real, a.imag + b.imag)
-(a::MyComplex, b::MyComplex) = MyComplex(a.real - b.real, a.imag - b.imag)
*(a::MyComplex, b::MyComplex) = MyComplex(
    a.real * b.real - a.imag * b.imag,
    a.real * b.imag + a.imag * b.real
)
abs(c::MyComplex) = sqrt(c.real^2 + c.imag^2)
show(io::IO, c::MyComplex) = print(io, "$(c.real) + $(c.imag)im")

c1 = MyComplex(1, 2)
c2 = MyComplex(3, 4)
c1 + c2
c1 * c2
abs(c1)

4.2 练习2:分数类型 #

julia
import Base: +, -, *, /, ==, show, convert

struct Fraction
    numerator::Int
    denominator::Int
    
    function Fraction(n::Int, d::Int)
        d == 0 && error("Denominator cannot be zero")
        g = gcd(n, d)
        new(n ÷ g, d ÷ g)
    end
end

+(a::Fraction, b::Fraction) = Fraction(a.numerator * b.denominator + b.numerator * a.denominator, a.denominator * b.denominator)
-(a::Fraction, b::Fraction) = Fraction(a.numerator * b.denominator - b.numerator * a.denominator, a.denominator * b.denominator)
*(a::Fraction, b::Fraction) = Fraction(a.numerator * b.numerator, a.denominator * b.denominator)
/(a::Fraction, b::Fraction) = Fraction(a.numerator * b.denominator, a.denominator * b.numerator)
==(a::Fraction, b::Fraction) = a.numerator == b.numerator && a.denominator == b.denominator
show(io::IO, f::Fraction) = print(io, "$(f.numerator)/$(f.denominator)")
convert(::Type{Float64}, f::Fraction) = f.numerator / f.denominator

Fraction(1, 2) + Fraction(1, 3)
Fraction(1, 2) * Fraction(2, 3)
Float64(Fraction(1, 3))

4.3 练习3:向量类型 #

julia
import Base: +, -, *, /, dot, norm, show

struct Vec3
    x::Float64
    y::Float64
    z::Float64
end

+(a::Vec3, b::Vec3) = Vec3(a.x + b.x, a.y + b.y, a.z + b.z)
-(a::Vec3, b::Vec3) = Vec3(a.x - b.x, a.y - b.y, a.z - b.z)
*(v::Vec3, s::Real) = Vec3(v.x * s, v.y * s, v.z * s)
*(s::Real, v::Vec3) = v * s
/(v::Vec3, s::Real) = Vec3(v.x / s, v.y / s, v.z / s)
dot(a::Vec3, b::Vec3) = a.x * b.x + a.y * b.y + a.z * b.z
norm(v::Vec3) = sqrt(dot(v, v))
show(io::IO, v::Vec3) = print(io, "Vec3($(v.x), $(v.y), $(v.z))")

v1 = Vec3(1, 2, 3)
v2 = Vec3(4, 5, 6)
v1 + v2
dot(v1, v2)
norm(v1)

五、总结 #

本章我们学习了:

  1. 方法重载概念:为已有函数添加新方法
  2. 运算符重载:自定义类型的运算符行为
  3. 常用重载函数:show、convert、promote、iterate
  4. 实践应用:复数、分数、向量类型

接下来让我们学习Julia的模块系统!

最后更新:2026-03-27