以下の内容はhttps://toyo.hatenablog.jp/entry/2025/03/25/202716より取得しました。


duck typing がわからんので調べてまとめる

「Goはダックタイピングだよ」と言われるケースをちょくちょく見かけたものの、本当にそうなの?となっていたので調べた。ここらへん、実はPHPがとても良い例になりそうなので、GoとPHPのコード例を出していきます。

Nominal Typing

まず一番わかりやすいものから。その型であるとするには、「その型だよ」と宣言する必要があるというもの。PHPJavaが採用している。

例えば、「にゃーんと鳴く」という猫インターフェースを定義する。このとき、ツイッターで「にゃーん」と鳴いているエンジニアおじさんを区別できるのが Nominal Typing 。

PHP は Nominal Typing を採用している。

<?php  

// Iterator型と認識される  
class CharacterIterator implements Iterator  
{  
    // ...  
}  


// Iterator型と認識されない  
class CountIterator  
{  
    // ...  
}  

Go は 後述する Structual Typing を採用しているので、Noming Typing ではない認識。

// Stringer を宣言していないが Stringer である  
type MyULID struct {  
    // ...  
}  

func (u MyULID) String() string {  
    // ...  
}  

structural typing

その型がインターフェースの形をしていれば、そのインターフェースを満たしていると見做すもの。GoやTypeScriptが採用している。

例えば、「にゃーんと鳴く」という猫インターフェースを定義する。このとき、Structural Typing ではツイッターで「にゃーん」と鳴いているエンジニアおじさんも猫であると見做す。

Goは structural typing を採用している。上述のコードを再掲。

// Stringer を宣言していないが Stringer である  
type MyULID struct {  
    // ...  
}  

func (u MyULID) String() string {  
    // ...  
}  

PHP は structural typing は採用していない。以下のコードの MyULIDtoInt() を実装しているが、 Intable とは見做されない。

<?php

interface Intable  
{  
    function toInt(): int;  
}  

// MyULID は Intable ではない  
class MyULID  
{  
    // ...  

    public function toInt(): int  
    {  
        // ...  
    }  
}  

function output(Intable $i) {  
    echo $i->toInt();  
}  

$id = new MyULID();  
output($id); // 型エラー  

duck typing

変数や値がそれを呼び出し可能であれば、それを呼び出せるというもの。PHPRubyが採用している。

例えば、$catmeow() というメソッドがあれば、meow()を呼び出せるというもの。

PHPは duck typing を採用している。下のコードは mixed 型の変数から meow() を呼び出しているが、meow()が存在していれば実行できるし、存在していなければエラーとなる。だが、少なくとも型チェックは通過する。

<?php

function getMeowable(): mixed  
{  
    // ...  
}  

$meowable = getMeowable();  
$meowable->meow();  

Go は duck typing ではない認識。以下のコードは meowableMeow() を実装しているにも関わらず、コンパイルエラーとなる。

type Meowable interface {  
    Meow()  
}  

// Cat は Meowable  
type Cat struct{}  

func (c Cat) Meow() {  
    // ...  
}  

func getMeowable() any {  
    return Cat{}  
}  

func main() {  
    meowable := getMeowable()  
    meowable.Meow() // コンパイルエラー  
}  

まとめ

typing PHP Go
nominal o x
structural x o
duck o x

nominal typing であり、 duck typing である PHP が少し異例な気がしてきた。




以上の内容はhttps://toyo.hatenablog.jp/entry/2025/03/25/202716より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14