约束关联类型

时间:2016-01-10 12:27:28

标签: swift swift-protocols associated-types

我的代码的简化版本,显示了问题:

protocol Transformer {
    typealias Input
    typealias Output

    func transform(s: Input) -> Output
}

protocol InputType {}
protocol OutputType {}

extension Int: OutputType {}
extension String: InputType {}

struct StringToInt: Transformer {
    typealias Input = String
    typealias Output = Int

    func transform(s: Input) -> Output {
        return s.characters.count
    }
}

typealias Transform = InputType -> OutputType

func convert<T: Transformer where T.Input == InputType, T.Output == OutputType>
    (transformer: T) -> Transform {
    return transformer.transform
}

convert(StringToInt()) // error: Cannot invoke 'convert' with an argument list of type '(StringToInt)'

我猜错了,因为编译器无法访问StringToInt并验证InputOutput确实符合InputTypeOutputType分别

对我来说,解决这个问题的最佳方法是直接在协议中约束相关类型。它会更具表现力,编译器会有更多信息。但只是做typealias Input: InputType不起作用。

有没有办法约束相关类型?

2 个答案:

答案 0 :(得分:1)

您可以为Transformer协议

创建扩展程序
extension Transformer where Input: InputType, Output: OutputType {
    func convert() -> Input -> Output {
        return transform
    }
}

现在,您可以在convert实例上调用StringToInt方法。

StringToInt().convert()

但对于其他没有InputOutput采用InputTypeOutputType的类型,它不会编译

struct DoubleToFloat: Transformer {
    func transform(s: Double) -> Float {
        return Float(s)
    }
}

DoubleToFloat().convert() // compiler error

答案 1 :(得分:0)

删除#include "tttfs.h" uint8_t little[4]; int tttfs_create(int size, char *name); void inttolitend(uint32_t x, uint8_t* lit_int); int main(){ tttfs_create(7, "disk.tfs"); } int tttfs_create(int size, char *name){ FILE *f = NULL; if ((f = fopen(name, "wb"))!=NULL) { disk *d = malloc(sizeof(disk)); d->diskBlock = malloc(1024); d->id = 1; int i; for(i = 0; i<size; i++){ printf("%d\n", i); d->diskBlock[i].unBlock = malloc(1024); //I got the segmentation fault here } inttolitend(size, little); for(i = 0; i<4; i++){ d->diskBlock[0].unBlock[i] = little[i]; } for(i = 0; i<size; i++){ fwrite(&d->diskBlock[i],1024,1,f); } } else printf("Erreur\n\n"); return 0; } void inttolitend(uint32_t x, uint8_t* lit_int){ lit_int[3] = (uint8_t)x / (256*256*256); lit_int[2] = (uint8_t)(x % (256*256*256)) / (256*256); lit_int[1] = (uint8_t)((x % (256*256*256)) % (256*256)) / 256; lit_int[0] = (uint8_t)((x % (256*256*256)) % (256*256)) % 256; } 别名用法,为输入和输出类型添加泛型,并将其映射到Transform,然后您将获得Transformer的工作代码以及你写的其他变形金刚:

StringToInt
顺便说一下,你不需要为func convert<T: Transformer, I, O where T.Input == I, T.Output == O> (transformer: T) -> I -> O { return transformer.transform } convert(StringToInt()) 指定类型别名,如果你指定了实际的类型,编译器就可以从函数定义中推断出那些:

StringToInt