如果我正确理解您的问题,我会说您不必考虑它,因为编译器会知道所需的类型。例如,在您上面的代码中,当您调用first(c)(这将相当于c.first())时,此变量的类型将在编译时已知(您可以通过@code_warntype在您的函数上运行来确认这一点)。
如果你能提供一个完整的小型工作示例,我可以给你一个工作代码。
一个更高级的主题是将一些元数据附加到您的类型。有几种方法可以做到。让我向您展示其中之一 - 通过参数抽象类型。
abstract type AbstractCollection{T} end
struct PersonalDetail end
struct AddressBook <: AbstractCollection{PersonalDetail} end
struct Photo end
struct PhotoAlbum <: AbstractCollection{Photo} end
getcollectiontype(::AbstractCollection{T}) where T = T
现在你可以写这样的东西来提取元数据
julia> ab = AddressBook()
AddressBook()
julia> pa = PhotoAlbum()
PhotoAlbum()
julia> getcollectiontype(ab)
PersonalDetail
julia> getcollectiontype(pa)
Photo
当然它是一个 MWE,我不确定你的代码中是否需要它(如果你展示一个小的完整工作代码,我们可以讨论最佳实施策略)。
也可能根本不需要这样的东西。例如,您有一个标准函数eltype,该函数应返回集合中的一种元素。对于此功能,您可以为您的特定类型添加方法以获取有关它们持有的元素类型的信息。然后您可以简单地eltype(collection)在您的代码中再次运行 - 在编译时 - 您将获得有关集合元素类型的信息。
另请注意,Julia 中的类型也是值,因此例如以下代码可以正常工作,并且编译器根据需要知道所有类型(该函数f尝试使用类型构造函数将其第二个参数转换为其第y一个参数x的类型):
julia> f(x,y) = typeof(x)(y)
f (generic function with 1 method)
julia> f(10, 2.0)
2
julia> f(10.0, 2)
2.0
julia> @code_warntype f(10.0, 2)
Body::Float64
1 ─ %1 = (Base.sitofp)(Float64, y)::Float64
└── return %1
上面的定义等价于下面的定义f(x::T,y) = T(y)。