繁体   English   中英

为什么Objective-C类和协议可以重名,而Swift不可以,语言实现有什么不同?

[英]Why does Objective-C class and protocol can have the same name, but Swift can't, what's the difference in language implementation?

Swift,无法编译,编译器会直接报错。

protocol Test {}

struct Test {}


// Swift compile output:

// Untitled.swift:4:8: error: invalid redeclaration of 'Test' struct Test {}

// Untitled.swift:2:10: note: 'Test' previously declared here protocol Test {}

Objective-C,可以编译成功,比如NSObject是类名,也是协议名

#import <Foundation/Foundation.h>

@protocol Test
@end

@interface Test
@end

int main(int argc, char *argv[]) {
    @autoreleasepool {
        NSLog(@"Hello word");
    }
}
// Objective-C output
// 2018-03-11 23:14:20.341 Untitled[34921:1272761] Hello word

Objective-C 和 Swift 有不同的名称解析方案,导致这种情况发生。

  1. 在 Objective-C 中,类名和协议名通常是唯一的。 (您始终可以注册一个与现有协议或类同名的新协议或类,但您通常会收到警告,并且肯定会出现异常行为。)但是,类名和协议名存在于不同的命名空间中——类名可以隐藏协议名称,反之亦然。 这通常没问题,因为类和协议在源代码中的引用方式不同:名为Foo的类由纯标识符Foo引用,而名为Foo的协议由@protocol(Foo)引用。 这里没有冲突。
  2. 然而,在 Swift 中,不同类型之间的名称解析没有区别。 协议名称与所有其他类型名称位于同一名称空间中,引用名为Foo的类和名为Foo的协议之间的语法没有区别,部分导致上述错误。

请注意,由于 Swift 中的名称解析方式, enum s/ struct s/ class es可以与协议具有相同的名称,反之亦然; 名称本身在 Swift 中不是唯一的,但完全限定的名称是。 您收到上述错误的原因实际上是因为struct Testprotocol Test都具有相同的完全限定名称: <name-of-your-module>.Test

但是,没有什么可以阻止您在不同的模块中声明struct Testprotocol Test ,因为它们具有不同的完全限定名称。 例如,欢迎您添加

struct ExpressibleByStringLiteral {}

到您的代码,尽管标准库提供了该名称的协议。 ExpressibleByStringLiteral然后会隐藏标识符的其他用法,因此要引用 stdlib 提供的协议,您需要使用Swift.ExpressibleByStringLiteral的完全限定名称:

struct ExpressibleByStringLiteral {}
struct S1 : ExpressibleByStringLiteral {} // error: inheritance from non-protocol type 'ExpressibleByStringLiteral'

struct S2 : Swift.ExpressiblyByStringLiteral {} // need to add methods to satisfy the protocol

这对 Swift 中的所有类型都是如此——多个类型可以有相同的名称,只要它们的完全限定名称是唯一的。

编译器可以根据上下文区分协议名称和类名称。 因此,如果您知道在何处将其用作协议以及在何处将其用作类,就不会产生歧义。

假设我们有一个符合Car协议的Car类。

@protocol Car <NSObject>
- (BOOL)canRun;
@end

@interface Car : NSObject <Car>
@end

@implementation Car
- (NSString *)description {
    return [NSString stringWithFormat:@"im a car"];
}
- (BOOL)canRun {
    return YES;
}
@end

您可以使用Car作为协议,编译器会知道它。

/* compiler tasks Car as a protocol*/
// 1
id<Car> car;

// 2
[obj comformsToProtocol: @protocol(Car)];

// 3
@interface Truck : NSObject <Car>
@end

// 4
@protocol AnotherProtocol <Car>
@end

您也可以将Car用作一个类,编译器也会识别它。

/* compiler tasks Car as a class*/
// 1 
Car *car = [Car new];

// 2
[Car someClassMethod];

// 3
@interface Truck : Car
@end

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM