2013-01-21 10 views
5

Tôi đang cố viết một gói trong Go để tính toán phương trình bằng loại "chung". Để cụ thể, tôi muốn triển khai xấp xỉ runge kutta 5.Go (ngôn ngữ) kiểu số/giao diện chung

xấp xỉ này tính toán giá trị của một (không rõ) chức năng y tại điểm t0 + h chỉ sử dụng các giá trị của y tại t0, thời gian bắt đầu t0, chiều rộng bước h và một phương trình vi phân dgl mà có dạng dy/dt = g(t,y) nơi g là một số chức năng.

Phép tính xấp xỉ này hoạt động giống hệt nhau khi làm việc với các loại vô hướng khi làm việc với vec-tơ (hoặc thậm chí ma trận). Nói chung hơn: Nó hoạt động với mọi thứ có thể được cộng/trừ vào giá trị cùng loại và có thể được thu nhỏ bằng vô hướng (mà tôi sử dụng float64)

Vì vậy, tôi đã cố gắng thể hiện điều này dưới dạng giao diện Go:

type Numeric interface { 
    Add(rhs Numeric) Numeric 
    Sub(rhs Numeric) Numeric 
    Mul(rhs float64) Numeric 
} 

Nhưng khi tôi cố gắng để "thực hiện" giao diện này, tôi chạy vào rắc rối vì các thông số gõ:

type Vec6F struct { 
    x, y, z float64 
    vx, vy, vz float64 
} 

func (lhs *Vec6F) Add(rhs *Vec6F) rk5.Numeric { 
    result := new(Vec6F) 
    result.x = lhs.x + rhs.x 
    result.y = lhs.y + rhs.y 
    result.z = lhs.z + rhs.z 
    result.vx = lhs.vx + rhs.vx 
    result.vy = lhs.vy + rhs.vy 
    result.vz = lhs.vz + rhs.vz 
    return result 
} 

này mang lại cho tôi những lỗi

cannot use result (type *Vec6F) as type rk5.Numeric in return argument: 
     *Vec6F does not implement rk5.Numeric (wrong type for Add method 
       have Add(*Vec6F) rk5.Numeric 
       want Add(rk5.Numeric) rk5.Numeric 

đó là, một mặt hoàn toàn logic để tôi (vì RHS có thể là một đối tượng thực hiện Numeric)

Nhưng mặt khác: Làm thế nào để thể hiện một cái gì đó như thế tại Gò? Trong C + +, tôi có thể sử dụng toán tử quá tải thay thế, nhưng điều đó không thể thực hiện được.

+0

"ngoài chủ đề": phương trình vi phân được giải quyết là phương trình mô tả quỹ đạo mars (đơn giản). Để biết mã hoàn chỉnh nhanh chóng, hãy xem http://play.golang.org/p/GwehylBbLK –

Trả lời

2

Để được chung, phương pháp Add của bạn phải có thông số Numeric. Theo cách thông thường để đối phó với điều này là với một loại khẳng định như thế này (on playground)

func (lhs *Vec6F) Add(_rhs Numeric) Numeric { 
    result := new(Vec6F) 
    rhs := _rhs.(*Vec6F) // type assertion - will panic if wrong type passes 
    result.x = lhs.x + rhs.x 
    result.y = lhs.y + rhs.y 
    result.z = lhs.z + rhs.z 
    result.vx = lhs.vx + rhs.vx 
    result.vy = lhs.vy + rhs.vy 
    result.vz = lhs.vz + rhs.vz 
    return result 
} 

Bạn cũng có thể sử dụng một công tắc kiểu nếu bạn có các loại khác nhau mà bạn muốn chuyển đổi giữa.

+0

Thx, đây có lẽ là giải pháp tôi sẽ kết thúc, mặc dù tôi không thích xác nhận kiểu. Bạn chuyển đổi sang kiểu con trỏ thay vì '_rhs. (Vec6F)' để an toàn một bản sao không cần thiết, đúng không? –

+0

Nó phải là một kiểu con trỏ để làm cho việc xác nhận kiểu hoạt động. Hãy thử thay đổi nó trên liên kết sân chơi ở trên để xem những gì tôi có nghĩa là - bạn sẽ nhận được lỗi "xác nhận loại không thể: Vec6F không thực hiện Numeric (Thêm phương pháp đòi hỏi người nhận con trỏ)" –

1

Thật vậy, thuốc generic không được hỗ trợ khi di chuyển. Nếu bạn muốn một loại để thực hiện một giao diện, các nguyên mẫu của phương thức cần phải khớp chính xác: bạn sẽ cần func (lhs *Vec6F) Add(rhs Numeric) Numeric.

Đây là một nỗ lực để viết phương pháp này sử dụng một loại khẳng định:

func (lhs *Vec6F) Add(rhs Numeric) Numeric { 
    vrhs := rhs.(*Vec6F) 
    result := new(Vec6F) 
    result.x = lhs.x + vrhs.x 
    result.y = lhs.y + vrhs.y 
    result.z = lhs.z + vrhs.z 
    result.vx = lhs.vx + vrhs.vx 
    result.vy = lhs.vy + vrhs.vy 
    result.vz = lhs.vz + vrhs.vz 
    return result 
} 

Nó biên dịch và nên làm việc khi được gọi với các loại quyền của đối số, tuy nhiên, tôi muốn nói đó là một sự lạm dụng.

Không có gì ngăn bạn (ngoại trừ lỗi thời gian chạy) sử dụng phương pháp này để thêm vectơ vào vô hướng vì cả hai đều thực hiện Numeric. Cuối cùng, bạn sẽ không nhận được gì từ việc sử dụng giao diện trừu tượng.

Triết lý đi sẽ dẫn đến việc sử dụng các phương pháp/chức năng kiểu cụ thể trong trường hợp này.

+2

Chính xác bạn có ý gì khi "sử dụng các phương pháp/chức năng kiểu cụ thể"? Bạn có thể đưa ra một ví dụ? –

+0

Như trong, bạn sẽ không có một chung chung mà làm việc trên Vec6F và số khác như các loại. Bạn sẽ có addVec6F, vv –

0

Có hai vấn đề bạn đang gặp phải.

1.) Lý do không biên dịch và khiếu nại về các giao diện không phù hợp là vì Vec6F không thỏa mãn chữ ký hàm cho rk5.Numeric. Cả hai giá trị trả về và tham số đầu vào phải khớp với loại.

http://play.golang.org/p/kc9V9EXxJq sửa chữa vấn đề đó, nhưng tạo ra một cái mới ...

2.) Để thực hiện các trận đấu phương pháp chữ ký để chữ ký Vec6F đáp ứng Numeric của nó đã phá vỡ khả năng thực hiện các hoạt động số trên giá trị tài sản.Điều này là do các giao diện chỉ có các phương thức, không có thuộc tính.

Trong trường hợp của bạn, sẽ có ý nghĩa đối với giao diện Số để cung cấp phương thức truy cập sẽ trả về mảng ma trận mà người nhận sau đó sẽ thực hiện Thêm | Sub | Đa trên? Điều này có thể phức tạp những gì cần phải được thực hiện trong mỗi phương pháp thực hiện giao diện nhưng tôi nghĩ rằng sẽ giúp bạn có được những gì bạn đang tìm kiếm.

+1

Bởi vì tôi cần kết quả (tính toán) khoảng 2 giờ trước, tôi đã thay đổi mã để sử dụng các slice float64 thay vào đó, đó là một phiên bản cấp tiến cung cấp phương thức truy cập như vậy. Mã hoàn chỉnh là tại http://play.golang.org/p/GwehylBbLK - Nó hoạt động, nhưng nó không phải là mã đẹp, theo ý kiến ​​của tôi. Vấn đề với phương thức accessor là như sau: Giả sử tôi phải sử dụng các số phức. Hoặc tôi chỉ muốn các giá trị Integer trong một trường hợp sử dụng khác. Cung cấp một accessor sau đó trở thành có lẽ không thể, như tôi couldnt chỉ hoạt động trên vectơ/ma trận mà còn trên đa thức. –