有人可以解释为什么NamedTuple
s 和 immutable struct
s 是分开的,而不是像匿名函数一样是匿名NamedTuple
的吗?它们在概念上看起来具有相同的结构(我也想知道它们是否具有不同的内存布局),尽管它们有不同的方法来访问它们的字段(下面的示例)。实现s的方法似乎非常合理,但我可能只是不知道不这样做的充分理由。struct
function (x) x^2 end
NamedTuple
struct
struct X; a; b; c; end
Xnt = NamedTuple{(:a,:b,:c), Tuple{Any, Any, Any}}
t1 = (10, 20.2, 30im)
#
#
# t1[1] indexing by position
# t1[1:2] slicing
# for el in t1 iteration
x1 = X(t1...)
# x1.a getting field
xnt1 = Xnt(t1)
# xnt1.a getting field
# xnt1[:a] indexing by field
# xnt1[1] indexing by position
#
# for el in t1 …
Run Code Online (Sandbox Code Playgroud) 当类型推断出现问题时(::Any
在@code_warntype
打印输出中),我的理解是函数调用是动态调度的。换句话说,在运行时,将检查参数的类型以查找MethodInstance
具体参数类型的特化 ( )。需要在运行时而不是编译时执行此操作会产生性能成本。
(编辑:最初,我在类型检查和专业化查找之间说“多重分派找到合适的方法”,但我实际上不知道这部分是否在运行时发生。似乎只有在没有有效的情况下才需要发生专业化是存在的,需要进行编译。)
在只需要检查一个参数的具体类型的情况下,是否可以进行更快的动态单分派,就像在某种专业化查找表中一样?我只是找不到一种访问和调用MethodInstance
s 的方法,就好像它们是函数一样。
当谈到改变调度或专业化时,我想到了invoke
和@nospecialize
。invoke
看起来它可能会直接跳到指定的方法,但检查多个参数类型和专业化仍然必须进行。@nospecialize
不会跳过调度过程的任何部分,只会导致不同的专业化。
编辑:一个带有注释的最小示例,希望能够描述我正在谈论的内容。
struct Foo end
struct Bar end
# want to dispatch only on 1st argument
# still want to specialize on 2nd argument
baz(::Foo, ::Integer) = 1
baz(::Foo, ::AbstractFloat) = 1.0
baz(::Bar, ::Integer) = 1im
baz(::Bar, ::AbstractFloat) = 1.0im
x = Any[Foo(), Bar(), Foo()]
# run test1(x, 1) or test1(x, 1.0)
function test1(x, second)
# first::Any in …
Run Code Online (Sandbox Code Playgroud)