如何从 Julia 中结构的构造函数中调用函数?
How to call function from within constructor of a struct in Julia?
我是一名拥有 C++ 和 Python 背景的程序员,最近偶然发现了 Julia,我真的很喜欢它所提供的功能。为了同时更加熟悉区块链实现和 Julia,我有点雄心勃勃,我试图通过转换 Python 发布的实现来在 Julia 中创建区块链的基本实现22=](作者解释了每种方法应该比我做得更好的地方)。
但是,在创建实际的 Blockchain
结构时,我 运行 遇到了问题。为了创建创世块,Hackernoon 建议我在构造函数中调用成员函数 new_block
。到目前为止,我还没有弄清楚如何在 Julia 中最好地复制它。这是我目前所拥有的:
import JSON
import SHA
mutable struct Blockchain
chain::Array{Dict{String, Any}}
current_transactions::Array{String}
block::Dict{String, Any}
new_block::Function
function Blockchain(chain::Array{Dict{String, Any}}, current::Array{String})
new(chain, current, new_block(previous_hash=1, proof=100))
# ^issue calling function within the constructor here
end
end
当我尝试 运行 我的代码时,出现以下错误:
invalid redefinition of constant Blockchain
.
这是 new_block
函数:
function new_block(proof::String, previous_hash::String=nothing)
block = Dict(
"index" => length(chain) + 1,
"timestamp" => time(),
"transactions" => current_transactions,
"proof" => proof,
"previous_hash" => previous_hash | hash(chain[end]),
)
current_transactions = []
append!(chain, block)
return block
end
以下是我目前拥有的其余功能:
function new_transaction(this::Blockchain, sender::String, recipient::String, amount::Int)
transaction = Dict(
"sender"=> sender,
"recipient"=> recipient,
"amount"=> amount,
)
append!(this.current_transactions, transaction)
return length(this.chain) + 1
end
function hash(block::Blockchain)
block_string = JSON.dumps(block, sort_keys=true).encode()
return sha256(block_string).hexdigest()
end
我可能对 types/structs 在 Julia 中的工作方式有一些误解;我的大部分信息连同官方文档都是从第三方网站获得的。以下是我一直依赖的一些来源:
- https://scls.gitbooks.io/ljthw/content/_chapters/06-ex3.html
- https://thenewphalls.wordpress.com/2014/02/19/understanding-object-oriented-programming-in-julia-part-1/
- https://juliabyexample.helpmanual.io/
Smarter/more 尝试完成我的目标的有效方法将不胜感激。
编辑:
以下是我根据给定的建议所做的一些更改:
struct Blockchain
chain::Array{Dict{String, Any}}
current_transactions::Array{String}
function Blockchain(chain::Array{Dict{String, Any}}, current::Array{String})
new(chain, current)
end
end
function new_block!(this::Blockchain, proof::Int, previous_hash::Int=nothing)
block = Dict(
"index" => length(this.chain) + 1,
"timestamp" => time(),
"transactions" => this.current_transactions,
"proof" => proof,
)
if previous_hash == nothing
block["previous_hash"] = hash(this.chain[end])
else
block["previous_hash"] = previous_hash
end
this.current_transactions = []
append!(this.chain, block)
return this
end
我意识到 block
属性没有用,因为它只是为了添加到 chain
而存在的,所以我删除了它。
此外,这里还有一个没有内部构造函数的替代 Blockchain
定义:
struct Blockchain
chain::Array{Dict{String, Any}}
current_transactions::Array{String}
Blockchain(x::Array{Dict{String, Any}}, y::Array{String}) = new(x, y)
end
免责声明。这可能不一定是您问题的答案。但我想 post 它作为一个答案,因为评论 而不是 让我很容易表达下面的内容。
mutable struct Blockchain
chain::Array{Dict{String, Any}}
current_transactions::Array{String}
block::Dict{String, Any}
new_block::Function
function Blockchain(chain::Array{Dict{String, Any}}, current::Array{String})
new(chain, current, new_block(previous_hash=1, proof=100))
# ^issue calling function within the constructor here
end
end
在这里,我假设您正在尝试 添加 一些成员函数功能到您的 struct
,因为您已经声明您来自 C++
背景。然而,这不是朱利安。在 Julia 中,正如@crstnbr 已经建议的那样,我们需要定义作用于对象的全局函数。惯例是您在函数末尾添加 !
以指示该函数将 至少 更改其参数之一。
然后,通过检查 new_block
:
的定义
function new_block(proof::String, previous_hash::String=nothing)
block = Dict(
"index" => length(chain) + 1, # which chain?
"timestamp" => time(),
"transactions" => current_transactions, # which current_transactions?
"proof" => proof,
"previous_hash" => previous_hash | hash(chain[end]), # which chain?
)
current_transactions = []
append!(chain, block) # which chain?
return block
end
我注意到几个严重的错误。首先,您尝试使用一些未定义的变量,例如 chain
和 current_transactions
。我假设,再次从 C++
,你认为 new_block
将是 Blockchain
的成员函数,因此, 可以看到 它的 chain
成员变量。这是 而不是 Julia
的工作方式。第二个问题是你如何尝试调用 new_block
:
new_block(previous_hash=1, proof=100)
这个调用完全错误。上面的调用符号依赖于 keyword arguments;但是,您的函数定义 only 具有位置参数。为了能够支持关键字参数,您需要将函数定义更改为如下所示:
function new_block(; proof::String, previous_hash::String=nothing)
# ^ note the semi-colon here
# ...
end
最后,您将 proof
和 previous_hash
定义为 String
类型,但用 1
、100
和 [=33 调用它们=],类型为 Int
、Int
和 Void
.
我无法理解您对区块链应用程序的设计选择,但我强烈建议您应该 step-by-step 通过更简单的示例来学习这门语言。例如,如果你只是尝试下面的例子,你就会明白类型注释在 Julia 中是如何工作的:
Main> f(s::String = nothing) = s
f (generic function with 2 methods)
Main> f()
ERROR: MethodError: no method matching f(::Void)
Closest candidates are:
f(::String) at none:1
f() at none:1
Stacktrace:
[1] f() at ./none:1
[2] eval(::Module, ::Any) at ./boot.jl:235
Main> g(s::String) = s
g (generic function with 1 method)
Main> g(100)
ERROR: MethodError: no method matching g(::Int64)
Closest candidates are:
g(::String) at none:1
Stacktrace:
[1] eval(::Module, ::Any) at ./boot.jl:235
Main> h1(var1 = 1, var2 = 100) = var1 + var2
h1 (generic function with 3 methods)
Main> h1(var2 = 5, var1 = 6)
ERROR: function h1 does not accept keyword arguments
Stacktrace:
[1] kwfunc(::Any) at ./boot.jl:237
[2] eval(::Module, ::Any) at ./boot.jl:235
最后一条评论是,据我从您的示例中可以看出,您不需要 mutable struct
。 struct
应该只是帮助您进行设计 --- 您仍然可以添加 to/modify 它的 chain
、current_transactions
和 block
变量。再次检查下面的简单示例:
Main> struct MyType
a::Vector{Float64}
end
Main> m = MyType([1,2,3]);
Main> append!(m.a, 4);
Main> m
MyType([1.0, 2.0, 3.0, 4.0])
您可以将上例中的 MyType
的 a
变量视为 C++
中的 double * const a
。您不允许更改a
以指向不同的内存位置,但您可以通过a
修改内存位置pointed-to。
简而言之,你应该绝对尝试从官方文档step-by-step学习语言,并且post这里涉及的问题真的 最少的例子。从这个意义上说,你的例子很复杂。
我是一名拥有 C++ 和 Python 背景的程序员,最近偶然发现了 Julia,我真的很喜欢它所提供的功能。为了同时更加熟悉区块链实现和 Julia,我有点雄心勃勃,我试图通过转换 Python 发布的实现来在 Julia 中创建区块链的基本实现22=](作者解释了每种方法应该比我做得更好的地方)。
但是,在创建实际的 Blockchain
结构时,我 运行 遇到了问题。为了创建创世块,Hackernoon 建议我在构造函数中调用成员函数 new_block
。到目前为止,我还没有弄清楚如何在 Julia 中最好地复制它。这是我目前所拥有的:
import JSON
import SHA
mutable struct Blockchain
chain::Array{Dict{String, Any}}
current_transactions::Array{String}
block::Dict{String, Any}
new_block::Function
function Blockchain(chain::Array{Dict{String, Any}}, current::Array{String})
new(chain, current, new_block(previous_hash=1, proof=100))
# ^issue calling function within the constructor here
end
end
当我尝试 运行 我的代码时,出现以下错误:
invalid redefinition of constant Blockchain
.
这是 new_block
函数:
function new_block(proof::String, previous_hash::String=nothing)
block = Dict(
"index" => length(chain) + 1,
"timestamp" => time(),
"transactions" => current_transactions,
"proof" => proof,
"previous_hash" => previous_hash | hash(chain[end]),
)
current_transactions = []
append!(chain, block)
return block
end
以下是我目前拥有的其余功能:
function new_transaction(this::Blockchain, sender::String, recipient::String, amount::Int)
transaction = Dict(
"sender"=> sender,
"recipient"=> recipient,
"amount"=> amount,
)
append!(this.current_transactions, transaction)
return length(this.chain) + 1
end
function hash(block::Blockchain)
block_string = JSON.dumps(block, sort_keys=true).encode()
return sha256(block_string).hexdigest()
end
我可能对 types/structs 在 Julia 中的工作方式有一些误解;我的大部分信息连同官方文档都是从第三方网站获得的。以下是我一直依赖的一些来源:
- https://scls.gitbooks.io/ljthw/content/_chapters/06-ex3.html
- https://thenewphalls.wordpress.com/2014/02/19/understanding-object-oriented-programming-in-julia-part-1/
- https://juliabyexample.helpmanual.io/
Smarter/more 尝试完成我的目标的有效方法将不胜感激。
编辑:
以下是我根据给定的建议所做的一些更改:
struct Blockchain
chain::Array{Dict{String, Any}}
current_transactions::Array{String}
function Blockchain(chain::Array{Dict{String, Any}}, current::Array{String})
new(chain, current)
end
end
function new_block!(this::Blockchain, proof::Int, previous_hash::Int=nothing)
block = Dict(
"index" => length(this.chain) + 1,
"timestamp" => time(),
"transactions" => this.current_transactions,
"proof" => proof,
)
if previous_hash == nothing
block["previous_hash"] = hash(this.chain[end])
else
block["previous_hash"] = previous_hash
end
this.current_transactions = []
append!(this.chain, block)
return this
end
我意识到 block
属性没有用,因为它只是为了添加到 chain
而存在的,所以我删除了它。
此外,这里还有一个没有内部构造函数的替代 Blockchain
定义:
struct Blockchain
chain::Array{Dict{String, Any}}
current_transactions::Array{String}
Blockchain(x::Array{Dict{String, Any}}, y::Array{String}) = new(x, y)
end
免责声明。这可能不一定是您问题的答案。但我想 post 它作为一个答案,因为评论 而不是 让我很容易表达下面的内容。
mutable struct Blockchain
chain::Array{Dict{String, Any}}
current_transactions::Array{String}
block::Dict{String, Any}
new_block::Function
function Blockchain(chain::Array{Dict{String, Any}}, current::Array{String})
new(chain, current, new_block(previous_hash=1, proof=100))
# ^issue calling function within the constructor here
end
end
在这里,我假设您正在尝试 添加 一些成员函数功能到您的 struct
,因为您已经声明您来自 C++
背景。然而,这不是朱利安。在 Julia 中,正如@crstnbr 已经建议的那样,我们需要定义作用于对象的全局函数。惯例是您在函数末尾添加 !
以指示该函数将 至少 更改其参数之一。
然后,通过检查 new_block
:
function new_block(proof::String, previous_hash::String=nothing)
block = Dict(
"index" => length(chain) + 1, # which chain?
"timestamp" => time(),
"transactions" => current_transactions, # which current_transactions?
"proof" => proof,
"previous_hash" => previous_hash | hash(chain[end]), # which chain?
)
current_transactions = []
append!(chain, block) # which chain?
return block
end
我注意到几个严重的错误。首先,您尝试使用一些未定义的变量,例如 chain
和 current_transactions
。我假设,再次从 C++
,你认为 new_block
将是 Blockchain
的成员函数,因此, 可以看到 它的 chain
成员变量。这是 而不是 Julia
的工作方式。第二个问题是你如何尝试调用 new_block
:
new_block(previous_hash=1, proof=100)
这个调用完全错误。上面的调用符号依赖于 keyword arguments;但是,您的函数定义 only 具有位置参数。为了能够支持关键字参数,您需要将函数定义更改为如下所示:
function new_block(; proof::String, previous_hash::String=nothing)
# ^ note the semi-colon here
# ...
end
最后,您将 proof
和 previous_hash
定义为 String
类型,但用 1
、100
和 [=33 调用它们=],类型为 Int
、Int
和 Void
.
我无法理解您对区块链应用程序的设计选择,但我强烈建议您应该 step-by-step 通过更简单的示例来学习这门语言。例如,如果你只是尝试下面的例子,你就会明白类型注释在 Julia 中是如何工作的:
Main> f(s::String = nothing) = s
f (generic function with 2 methods)
Main> f()
ERROR: MethodError: no method matching f(::Void)
Closest candidates are:
f(::String) at none:1
f() at none:1
Stacktrace:
[1] f() at ./none:1
[2] eval(::Module, ::Any) at ./boot.jl:235
Main> g(s::String) = s
g (generic function with 1 method)
Main> g(100)
ERROR: MethodError: no method matching g(::Int64)
Closest candidates are:
g(::String) at none:1
Stacktrace:
[1] eval(::Module, ::Any) at ./boot.jl:235
Main> h1(var1 = 1, var2 = 100) = var1 + var2
h1 (generic function with 3 methods)
Main> h1(var2 = 5, var1 = 6)
ERROR: function h1 does not accept keyword arguments
Stacktrace:
[1] kwfunc(::Any) at ./boot.jl:237
[2] eval(::Module, ::Any) at ./boot.jl:235
最后一条评论是,据我从您的示例中可以看出,您不需要 mutable struct
。 struct
应该只是帮助您进行设计 --- 您仍然可以添加 to/modify 它的 chain
、current_transactions
和 block
变量。再次检查下面的简单示例:
Main> struct MyType
a::Vector{Float64}
end
Main> m = MyType([1,2,3]);
Main> append!(m.a, 4);
Main> m
MyType([1.0, 2.0, 3.0, 4.0])
您可以将上例中的 MyType
的 a
变量视为 C++
中的 double * const a
。您不允许更改a
以指向不同的内存位置,但您可以通过a
修改内存位置pointed-to。
简而言之,你应该绝对尝试从官方文档step-by-step学习语言,并且post这里涉及的问题真的 最少的例子。从这个意义上说,你的例子很复杂。