Goではインターフェース型で実装された関数を全て実装すれば、その型で振舞うことができます。
ダック・タイピングなアプローチができるので、これが扱えるのと扱えないのではコードに差が出てくるなと感じます。
一旦慣れてしまえば簡単に使えるのですが、わからない人向けに感覚値として掴んでもらえればと思って明示的な方法でインターフェースの実装を他の言語に置き換えています。
Goのファイルに関して、今回はインターフェースを埋め込んでいるため、仮にSounds
関数を実装していなくてもビルドが通ります。
ですが、もちろんのこと実装していないため、ランタイムエラーとなります。
そこの違いもいろいろ触ってもらえればと。(ビルドエラーかランタイムエラーか、実装変えるとどうなるかなどなど)
一部だけ解説します。
Goでは宣言したinterfaceの実装さえされていれば、その型で振舞われるため、わざわざインターフェースを埋め込まなくてもよいです。
よくわからないければ、作り手の意思としてチョイスする感じでよいかと。(適当)
package main
import "fmt"
type Animal interface {
sounds() string
}
type Cat struct {
Animal
Name string
}
func (c Cat) sounds() string {
return "Meow"
}
func call(a Animal) {
fmt.Println(a.sounds())
}
func main() {
cat := Cat{Name: "NyanCat"}
call(cat)
}
Swiftのprotocolでは、Objective-C時代にあった@optional
にあたるものがなくなりました。
そのため、protocol実装されたオブジェクトに関して必ず実装する必要があるため、ランタイムエラーとなり得る実装は無理な気がしました。柔軟ではないですね。(さすが堅牢をうたっているだけある(褒めてます。褒めてます。
protocol Animal {
func sounds() -> String
}
struct Cat: Animal {
var name: String
init(name: String) {
self.name = name
}
func sounds() -> String {
return "Meow"
}
}
func call(a : Animal) {
println(a.sounds())
}
func main() {
var cat = Cat(name: "NyanCat")
call(cat)
}
main()
Objective-Cには@optional
があるため、- (NSString *)sounds;
を実装しなくてもビルドが通ります。
が、もちろんメソッドがない場合はランタイムエラーとなります。
#import <Foundation/Foundation.h>
@protocol Animal
@optional
- (NSString *)sounds;
@end
@interface Cat : NSObject <Animal>
@property (nonatomic, strong) NSString *name;
@end
@implementation Cat
- (NSString *)sounds {
return @"Meow";
}
@end
void call(NSObject<Animal> *a) {
printf("%s\n", [[a sounds] UTF8String]);
}
int main(int argc, char *argv[])
{
Cat *cat = [Cat new];
cat.name = @"NyanCat";
call(cat);
return 0;
}