[解決済み] 汎用プロトコルを変数の型として使用する方法
質問
あるプロトコルがあるとします。
public protocol Printable {
typealias T
func Print(val:T)
}
そして以下はその実装です。
class Printer<T> : Printable {
func Print(val: T) {
println(val)
}
}
私が期待していたのは、このように
Printable
変数を使って、このような値を表示できるに違いないと思っていました。
let p:Printable = Printer<Int>()
p.Print(67)
コンパイラはこのエラーで文句を言っています。
プロトコル 'Printable'は、Selfまたは関連する型要件があるため、一般制約としてのみ使用することができます。 自己または関連する型の要件があるためです。
私は何か間違ったことをしているのでしょうか?どうすればいいですか?
**EDIT :** Adding similar code that works in C#
public interface IPrintable<T>
{
void Print(T val);
}
public class Printer<T> : IPrintable<T>
{
public void Print(T val)
{
Console.WriteLine(val);
}
}
//.... inside Main
.....
IPrintable<int> p = new Printer<int>();
p.Print(67)
EDIT 2: 私が欲しいものの実例です。これはコンパイルされませんが、私が達成したいことを提示していることに注意してください。
protocol Printable
{
func Print()
}
protocol CollectionType<T where T:Printable> : SequenceType
{
.....
/// here goes implementation
.....
}
public class Collection<T where T:Printable> : CollectionType<T>
{
......
}
let col:CollectionType<Int> = SomeFunctiionThatReturnsIntCollection()
for item in col {
item.Print()
}
どのように解決するのですか?
Thomas が指摘するように、型を全く与えないで変数を宣言することもできます(あるいは、明示的に型を与えることもできますが
Printer<Int>
. しかし、ここでは、なぜ型として
Printable
というプロトコルがあります。
関連する型を持つプロトコルを通常のプロトコルのように扱い、独立した変数型として宣言することはできません。 その理由を考えるために、次のようなシナリオを考えてみましょう。 ある任意の型を保存し、それを取り返すためのプロトコルを宣言したとします。
// a general protocol that allows for storing and retrieving
// a specific type (as defined by a Stored typealias
protocol StoringType {
typealias Stored
init(_ value: Stored)
func getStored() -> Stored
}
// An implementation that stores Ints
struct IntStorer: StoringType {
typealias Stored = Int
private let _stored: Int
init(_ value: Int) { _stored = value }
func getStored() -> Int { return _stored }
}
// An implementation that stores Strings
struct StringStorer: StoringType {
typealias Stored = String
private let _stored: String
init(_ value: String) { _stored = value }
func getStored() -> String { return _stored }
}
let intStorer = IntStorer(5)
intStorer.getStored() // returns 5
let stringStorer = StringStorer("five")
stringStorer.getStored() // returns "five"
OK、ここまでは順調です。
さて、変数の型を実際の型ではなく、型が実装するプロトコルにする主な理由は、そのプロトコルに準拠した異なる種類のオブジェクトを同じ変数に代入し、オブジェクトが実際に何であるかに応じて実行時に多相な振る舞いを得られるようにするためです。
しかし、プロトコルが関連する型を持っている場合、これを行うことはできません。 以下のコードは実際にどのように動作するでしょうか?
// as you've seen this won't compile because
// StoringType has an associated type.
// randomly assign either a string or int storer to someStorer:
var someStorer: StoringType =
arc4random()%2 == 0 ? intStorer : stringStorer
let x = someStorer.getStored()
上のコードで
x
の型は何でしょうか? アン
Int
? それとも
String
? Swiftでは、すべての型はコンパイル時に固定されていなければなりません。 関数は、実行時に決定された要因に基づいて、1つの型を返すことから別の型に動的に移行することはできません。
その代わりに
StoredType
を一般的な制約として使うだけです。 例えば、あらゆる種類の保存された型を出力したいとします。 このような関数を書くことができます。
func printStoredValue<S: StoringType>(storer: S) {
let x = storer.getStored()
println(x)
}
printStoredValue(intStorer)
printStoredValue(stringStorer)
これは、コンパイル時に、コンパイラが2つのバージョンの
printStoredValue
に対して
Int
のためのもの、そして
String
s. その2つのバージョンの中で
x
は特定のタイプであることが知られています。
関連
-
[解決済み] リフレクションを使ってジェネリックメソッドを呼び出すにはどうしたらいいですか?
-
[解決済み] Javaで汎用配列を作成する方法は?
-
[解決済み] 汎用型Tのクラスインスタンスを取得する方法を教えてください。
-
[解決済み] 汎用クラスやメソッドのメンバからTの型を取得する方法
-
[解決済み] iOS7でスタイルUITableViewStyleGroupedを持つUITableViewの上部に余分なパディングがあるのはなぜですか?
-
[解決済み] メソッドの戻り値の型を汎用的にするにはどうすればよいですか?
-
[解決済み] UIViewの左上と右上だけにcornerRadiusを設定する方法は?
-
[解決済み] NSOperationとGrand Central Dispatchの比較
-
[解決済み】TをEnumに拘束するGenericメソッドの作成
-
[解決済み】iOSアプリの名前を変更する方法は?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
libc++abi.dylib が NSException 型の捕捉できない例外で終了する理由 エラー
-
IOSラーニングノート「このクラスはxxxのキーバリューコーディングに対応していません」問題解決
-
EXC_BAD_ACCESS (code=2, address=0x0)
-
IOS8 Development Guide Error Thread 1: signal SIGABRT
-
[解決済み] SwiftでStringを配列に分割する?
-
[解決済み] iOS7でスタイルUITableViewStyleGroupedを持つUITableViewの上部に余分なパディングがあるのはなぜですか?
-
[解決済み] UIViewの左上と右上だけにcornerRadiusを設定する方法は?
-
[解決済み] iOSとWatchKitで画像のtintColorを変更する方法
-
[解決済み] UIImageのサイズを変更する最も簡単な方法?
-
[解決済み] セキュリティで保護されたWebサービスにもアクセスするiOSアプリで、Facebook認証を行うためのデザイン