みなさんこんにちは! 最近、私はGoでの空のインターフェイスの実装について書きました。その記事はご想像のとおり、GoでのOSの開発に直接関連していますが、このトピックは放棄されたり忘れられたりすることはなく、長い間延期されました。
カットの下で:asmプロキシメソッドを「破棄」し、panic()メソッドを実装し、ランタイムエラーをサポートします。
asmのすべてのスタブメソッドとプロキシメソッドを覚えていますか? 捨てて忘れてください。 残りのファイルは、multiboot.sとruntime.sの2つだけです。multiboot.sの内容は変更されず、runtime.sはこれに縮小されます。
global dummy dummy: ; ret global __unsafe_get_addr; convert uint32 to pointer __unsafe_get_addr: push ebp mov ebp, esp mov eax, [ebp+8] mov esp, ebp pop ebp ret
残りはすべて容赦なくナイフの下に置いた。
DATAタスクの後に、テキストセクションでlink.ldを開きます。
__go_new = go.runtime.New; __go_new_nopointers = go.runtime.New; __go_print_string = go.screen.PrintStr; __go_print_empty_interface = go.screen.PrintInterface; __go_print_nl = go.screen.PrintNl; __go_print_pointer = go.screen.PrintHex; __go_print_uint64 = go.screen.PrintUint64; __go_runtime_error = go.runtime.RuntimeError; __go_panic = go.runtime.Panic; runtime.efacetype = go.runtime.InterfaceType; runtime.ifacetypeeq = go.runtime.InterfaceTypeEq; runtime.ifaceE2T2 = go.runtime.InterfaceE2T2; __go_type_hash_identity = go.runtime.TypeHashIdentity; __go_type_equal_identity = go.runtime.TypeEqualIdentity; __go_strcmp = go.runtime.StrCmp; __go_type_hash_error = dummy; __go_type_equal_error = dummy; __go_register_gc_roots = dummy; __go_type_hash_identity_descriptor = dummy; __go_type_equal_error_descriptor = dummy; __go_type_equal_identity_descriptor = dummy; __go_type_hash_error_descriptor = dummy; __go_type_hash_empty_interface = dummy; __go_empty_interface_compare = dummy; __go_type_hash_string = dummy; __go_type_equal_string = dummy; __go_type_equal_empty_interface = dummy; __go_type_hash_string_descriptor = dummy; __go_type_equal_string_descriptor = dummy; __go_type_hash_empty_interface_descriptor = dummy; __go_type_equal_empty_interface_descriptor = dummy;
はい、急いで警告します。実装した方法の一部はまだ説明されていないため、ダミーに置き換えるか、自分で実装する必要があります。
ここで何が起こっていますか? シンボルエイリアスを作成します。これは、asmでプロキシメソッドを記述するよりもはるかに優れたソリューションです。
さて、私が捨てたasm-proxyを約束したので、パニックメソッドの実装に取り掛かりましょう。
この記事から 、TypeDescriptor、EmptyInterface、およびUncommonの構造をruntime.goファイルにコピーします。
追加する:
正直なところ、パニック引数が文字列である場合、ここで終了できますが、悲しいかな-空のインターフェイスなので、空のインターフェイスの印刷を実装し、それに応じてインターフェイスを型にキャストする必要があります、これを行います。 ワーニング:このセクションで書かれたすべてのコードはMVPの初期段階の鮮明な例であり、もちろん動作しますが、あまりにも原始的であり、欠陥があります。
runtime.goでまだ作業中であることを思い出させてください。
screen.goファイルに切り替えます。
さて、コード(kernel.go、Loadメソッド)を記述できます。
panic("Habrahabr")
そして、qemuの出力に感心します。
panic: Habrahabr
すでに悪くないですよね? しかし、ランタイムエラー処理も約束しました。
runtime.go:
したがって、今、どこかでミスをすると、それについてのメッセージが表示されます。
ワーニング:前の部分のコードは
多くのランタイムエラーを生成しますが、今のところそれらを修正する方法は示しません。宿題にしましょう。
記事の準備にご協力いただきありがとうございます:
Victorya1-校正、
ラフニングkirill_danshin-それらの議論。 パーツ、興味深い議論
UPD:文字列型へのインターフェイスのキャストの問題に関する興味深い議論
キリル:
私の考えは何ですか
[12:09:22 PM]イヴァン:
注意深く読んだ)
[12:09:35 PM]キリル:
gosh文字列は不変です
[12:09:45 PM]イヴァン:
うん
変更は新しいものの作成につながります
[12:10:25 PM]キリル:
InterfaceE2T2は、理論上、データをコピーしない場合があります
既存のものを参照
[12:12:47 PM]イヴァン:
それはできません、a)文字列だけでなく、b)戻りアドレスを取得し、さらに、ポインタではなく、期待されるタイプのデータをそこに書き込む必要があります
[12:13:31 PM]キリル:
私は何かを見落としていました
申し訳ありませんが、それはできません
私はいつも食べ物のこの制限に休みます
結局のところ、ここでは修正することはできません
[12:16:05 PM]イヴァン:
なぜ、ランタイムの拡張によって可能になるのか、つまり InterfaceToString(iface interface {})メソッドを実装します(str * string、ok bool)
しかし、これはランタイムメソッドではなく、ユーザーになります
うーん...この小さな議論を記事に追加しますか?
[12:17:01 PM]キリル:
はい、来ます
これは興味深いタスクです。遅かれ早かれ解決する必要があります
まったく同じインターフェイス{}-> []バイト
UPD2: Cyrilとの議論から関数を実装しようとしました。