2015-06-10 20 views
9

Tôi muốn sử dụng một kiểu con của tham số hàm trong định nghĩa hàm của mình. Điều này có thể không? Ví dụ, tôi muốn viết một cái gì đó như:Tôi có thể sử dụng một kiểu con của tham số hàm trong định nghĩa hàm không?

g{T1, T2<:T1}(x::T1, y::T2) = x + y 

Vì vậy mà g sẽ được xác định đối với bất kỳ x::T1 và bất kỳ y đó là một subtype của T1. Rõ ràng, nếu tôi biết, ví dụ, rằng T1 sẽ luôn luôn là Number, sau đó tôi có thể viết g{T<:Number}(x::Number, y::T) = x + y và điều này sẽ làm việc tốt. Nhưng câu hỏi này là dành cho trường hợp T1 không được biết đến cho đến khi chạy.

Đọc nếu bạn đang tự hỏi tại sao tôi muốn làm điều này:

Một mô tả đầy đủ về những gì tôi đang cố gắng để làm sẽ là một chút rườm rà, nhưng những gì sau là một ví dụ đơn giản.

Tôi có một loại parameterised, và một phương pháp đơn giản định nghĩa trên kiểu đó:

type MyVectorType{T} 
    x::Vector{T} 
end 
f1!{T}(m::MyVectorType{T}, xNew::T) = (m.x[1] = xNew) 

Tôi cũng có một kiểu khác, với một bản tóm tắt siêu kiểu định nghĩa như sau

abstract MyAbstract 
type MyType <: MyAbstract ; end 

tôi tạo một thể hiện của MyVectorType với loại phần tử vectơ được đặt thành MyAbstract sử dụng:

m1 = MyVectorType(Array(MyAbstract, 1)) 

Tôi muốn đặt một phiên bản MyType vào MyVectorType. Tôi có thể làm điều này, kể từ MyType <: MyAbstract. Tuy nhiên, tôi không thể làm điều này với f1!, vì định nghĩa hàm nghĩa là xNew phải thuộc loại TT sẽ là MyAbstract, không phải MyType.

Hai giải pháp tôi có thể nghĩ ra cho vấn đề này là:

f2!(m::MyVectorType, xNew) = (m.x[1] = xNew) 
f3!{T1, T2}(m::MyVectorType{T1}, xNew::T2) = T2 <: T1 ? (m.x[1] = xNew) : error("Oh dear!") 

Đầu tiên về bản chất là một giải pháp vịt-gõ. Thứ hai thực hiện kiểm tra lỗi thích hợp trong bước đầu tiên.

Được ưu tiên hơn? Hoặc là có một giải pháp thứ ba, tốt hơn tôi không biết?

Trả lời

11

Khả năng xác định hàm g{T, S<:T}(::Vector{T}, ::S) đã được gọi là "công văn tam giác" như một phép so sánh với công văn đường chéo: f{T}(::Vector{T}, ::T). (Hãy tưởng tượng một bảng có phân cấp kiểu ghi nhãn các hàng và cột, được sắp xếp sao cho các kiểu siêu là ở trên cùng và bên trái. Các hàng đại diện cho kiểu phần tử của đối số đầu tiên và các cột loại thứ hai. chỉ khớp các ô dọc theo đường chéo của bảng, trong khi công văn hình tam giác khớp với đường chéo và mọi thứ bên dưới nó, tạo thành hình tam giác.)

Điều này đơn giản là chưa được triển khai . Đó là một vấn đề phức tạp, đặc biệt là khi bạn bắt đầu xem xét phạm vi TS ngoài định nghĩa chức năng và trong ngữ cảnh bất biến. Xem issue #3766#6984 để biết thêm chi tiết.


Vì vậy, trên thực tế, trong trường hợp này, tôi cho rằng việc nhập vịt là tốt. Bạn đang dựa vào việc thực hiện myVectorType để thực hiện kiểm tra lỗi khi nó gán các phần tử của nó, nó sẽ làm gì trong mọi trường hợp.

Các giải pháp trong julia cơ sở cho việc thiết lập các yếu tố của một mảng là một cái gì đó như thế này: "tam giác"

f!{T}(A::Vector{T}, x::T) = (A[1] = x) 
f!{T}(A::Vector{T}, x) = f!(A, convert(T, x)) 

Lưu ý rằng nó không phải lo lắng về hệ thống phân cấp loại hoặc subtype Nó chỉ cố gắng chuyển đổi x thành T… là số không-op nếu x::S, S<:T. Và convert sẽ phát ra lỗi nếu nó không thể thực hiện chuyển đổi hoặc không biết cách thực hiện.


UPDATE: này bây giờ được thực hiện trên các phiên bản phát triển mới nhất (0.6-dev)! Trong trường hợp này, tôi nghĩ tôi vẫn khuyên bạn nên sử dụng convert như tôi đã trả lời ban đầu, nhưng bây giờ bạn có thể xác định các hạn chế trong các tham số phương thức tĩnh theo cách từ trái sang phải.

julia> f!{T1, T2<:T1}(A::Vector{T1}, x::T2) = "success!" 

julia> f!(Any[1,2,3], 4.) 
"success!" 

julia> f!(Integer[1,2,3], 4.) 
ERROR: MethodError: no method matching f!(::Array{Integer,1}, ::Float64) 
Closest candidates are: 
    f!{T1,T2<:T1}(::Array{T1,1}, ::T2<:T1) at REPL[1]:1 

julia> f!([1.,2.,3.], 4.) 
"success!" 
+1

Câu trả lời rất hữu ích - Tôi đã học được rất nhiều. Cảm ơn nhiều. –

Các vấn đề liên quan