ฉันจะดึงข้อโต้แย้งคำหลักออกจากเขตข้อมูลของ kwargs แบบ splatted ได้อย่างไร


9

หากฉันมีฟังก์ชันคล้ายลายเซ็นf(args...; kwargs...)ฉันจะลบคำหลักที่เฉพาะเจาะจงออกได้kwargsอย่างไร การพิมพ์อย่างไร้ค่า kwargs.xไม่ทำงาน:

julia> f(args...; kwargs...) = kwargs.x
f (generic function with 1 method)

julia> f(x=1)
ERROR: type Pairs has no field x
Stacktrace:
 [1] getproperty(::Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:x,),Tuple{Int64}}}, ::Symbol) at ./Base.jl:20
 [2] #f#7(::Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:x,),Tuple{Int64}}}, ::typeof(f)) at ./REPL[2]:1
 [3] (::var"#kw##f")(::NamedTuple{(:x,),Tuple{Int64}}, ::typeof(f)) at ./none:0
 [4] top-level scope at REPL[3]:1

คำถามนี้ปรากฏในช่อง JuliaLang Slack ใน #helpdesk สำหรับการเชิญอัตโนมัติไปยังการหย่อน julia ที่มีประโยชน์มากเพียงกรอกhttps://slackinvite.julialang.org

คำตอบ:


10

สาเหตุที่เกิดขึ้นคืออาร์กิวเมนต์ของคำหลักแบบแยกส่วนจะไม่ถูกเก็บไว้ใน tuple ที่มีชื่อตามค่าเริ่มต้น เราสามารถดูว่าพวกเขาเก็บไว้อย่างไร:

julia> g(;kwargs...) = kwargs
g (generic function with 1 method)

julia> g(a=1)
pairs(::NamedTuple) with 1 entry:
  :a => 1

julia> g(a=1) |> typeof
Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:a,),Tuple{Int64}}}

ดังนั้น kwargs ที่ splatted จะถูกเก็บไว้เป็นวัตถุตัววนซ้ำบางชนิดแทน อย่างไรก็ตามเราสามารถแปลงตัวkwargsวนซ้ำนั้นเป็น NamedTuple ได้อย่างง่ายดาย(;kwargs...)แล้วเข้าถึงในแบบที่เราคาดหวังดังนั้นตัวอย่างของคุณจะแปลเป็น

julia> f(args...; kwargs...) = (;kwargs...).x
f (generic function with 1 method)

julia> f(x=1, y=2)
1

แน่นอนว่าวิธีที่ใช้สำนวนมากกว่านี้คือการเขียนฟังก์ชั่นแทน

julia> f(args...; x, kwargs...) = x
f (generic function with 1 method)

julia> f(x=1, y=2)
1

แต่สิ่งนี้จะถือว่าคุณรู้ชื่อที่คุณต้องการเข้าถึง ( x) ในเวลาที่คุณเขียนฟังก์ชั่น


sidenote สั้น ๆ : ถ้าเรากลับไปที่ตัวอย่างของg(;kwargs...) = kwargsเราเราสามารถขอชื่อฟิลด์ของวัตถุตัววนซ้ำที่ถูกส่งคืนดังนี้:

julia> g(x=1, y=2) |> typeof |> fieldnames
(:data, :itr)

หืมdataฟิลด์นี้คืออะไร?

julia> g(x=1, y=2).data
(x = 1, y = 2)

Aha! เพื่อให้เราสามารถรับ kwargs เป็น tuple ที่ตั้งชื่อโดยใช้นั่นคือf(;kwargs...) = kwargs.data.xทำงานได้ แต่ฉันไม่แนะนำวิธีนี้เนื่องจากดูเหมือนจะขึ้นอยู่กับพฤติกรรมที่ไม่มีเอกสารดังนั้นจึงอาจเป็นเพียงรายละเอียดการใช้งานที่ไม่รับประกันว่าจะมั่นคง ข้ามรุ่น julia

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.