Julia中Base.@kwdef结构体初始化的方法调用问题求助
Julia结构体初始化中调用内部函数的问题
问题场景
尝试用Base.@kwdef定义包含物理/数值参数与初始化数组的可变结构体时,遇到两个报错:
- 最初代码中,在初始化
C0 = ic.(xc)时提示ic未定义,因为结构体内部定义的ic不在全局作用域:
Base.@kwdef mutable struct Setup # physics lx = 20.0 dc = 1.0 n = 4 # initial condition ic(x) = exp(-(x-lx/4)^2) # numerics nx = 200 nvis = 50 # derived numerics dx = lx/nx dt = dx^2/dc/10 nt = nx^2 ÷ 5 # arrays xc = LinRange(dx/2,lx-dx/2,nx) C0 = ic.(xc) C = copy(C) # 此处存在笔误,应为copy(C0) q = zeros(nx-1) # collections for easy use dgl_params=[dc,n] end
- 尝试外部构造器后,报错
DataType has no field ic——因为无法通过结构体类型直接访问实例的ic方法,且Julia没有self/this关键字:
Base.@kwdef mutable struct Setup # physics lx = 20.0 dc = 1.0 n = 4 # initial condition ic(x) = exp(-(x-lx/4)^2) # numerics nx = 200 nvis = 50 # derived numerics dx = lx/nx dt = dx^2/dc/10 nt = nx^2 ÷ 5 # arrays xc = LinRange(dx/2,lx-dx/2,nx) C0 C = copy(C) q = zeros(nx-1) # collections for easy use dgl_params=[dc,n] end function Setup() Setup(Setup.ic(Setup.xc)) end Setup()
注:dx、dt能正常工作是因为它们是字段默认值,Julia允许默认值引用之前定义的字段,但结构体内部定义的函数不属于字段,无法被默认值表达式访问。
解决方法
方法1:将ic设为可配置的字段(最简洁)
把ic定义为结构体的字段,默认值用依赖lx的匿名函数,这样初始化C0时可直接调用:
Base.@kwdef mutable struct Setup # physics lx = 20.0 dc = 1.0 n = 4 # initial condition 作为字段,保留可配置性 ic = x -> exp(-(x - lx/4)^2) # numerics nx = 200 nvis = 50 # derived numerics dx = lx/nx dt = dx^2/dc/10 nt = nx^2 ÷ 5 # arrays xc = LinRange(dx/2, lx - dx/2, nx) C0 = ic.(xc) C = copy(C0) # 修正之前的笔误 q = zeros(nx-1) # collections for easy use dgl_params = [dc, n] end # 测试 s = Setup() println(s.C0[1:5])
方法2:用内部构造器封装初始化逻辑
若不想暴露ic为字段,可将所有初始化逻辑放在内部构造器中,ic作为构造器内的局部函数:
mutable struct Setup # 声明所有字段类型 lx :: Float64 dc :: Float64 n :: Int nx :: Int nvis :: Int dx :: Float64 dt :: Float64 nt :: Int xc :: LinRange{Float64} C0 :: Vector{Float64} C :: Vector{Float64} q :: Vector{Float64} dgl_params :: Vector{Any} # 内部构造器处理默认值与C0初始化 function Setup(; lx=20.0, dc=1.0, n=4, nx=200, nvis=50 ) dx = lx / nx dt = dx^2 / dc / 10 nt = nx^2 ÷ 5 xc = LinRange(dx/2, lx - dx/2, nx) # 局部定义初始化函数 ic(x) = exp(-(x - lx/4)^2) C0 = ic.(xc) C = copy(C0) q = zeros(nx-1) dgl_params = [dc, n] # 返回结构体实例 new(lx, dc, n, nx, nvis, dx, dt, nt, xc, C0, C, q, dgl_params) end end # 测试 s = Setup() println(s.C0[1:5])
方法3:实例创建后补全C0
若需保留Base.@kwdef的简洁性,可先声明字段类型,创建实例后再调用初始化函数补全C0:
Base.@kwdef mutable struct Setup # physics lx = 20.0 dc = 1.0 n = 4 # numerics nx = 200 nvis = 50 # derived numerics dx = lx/nx dt = dx^2/dc/10 nt = nx^2 ÷ 5 # arrays xc = LinRange(dx/2,lx-dx/2,nx) C0 :: Vector{Float64} # 仅声明类型,暂不赋值 C = copy(C0) q = zeros(nx-1) # collections for easy use dgl_params=[dc,n] end # 定义初始化函数 function init_C0!(s::Setup) ic(x) = exp(-(x - s.lx/4)^2) s.C0 = ic.(s.xc) s.C = copy(s.C0) # 同步更新C end # 使用方式 s = Setup(C0=zeros(200)) # 先传入临时占位的C0 init_C0!(s) println(s.C0[1:5])
内容的提问来源于stack exchange,提问作者TheFibonacciEffect
相关产品推荐
相关产品推荐

