Джулия, похоже, не использует string для выполнения интерполяции

#string #julia #string-interpolation

#строка #джулия #строка-интерполяция

Вопрос:

В официальных документах указано:

Как конкатенация, так и интерполяция строк вызывают string() преобразование объектов в строковую форму

Однако следующий минимальный рабочий пример, похоже, демонстрирует обратное:

 type MyType
    x::Int
end
import Base.string
Base.string(m::MyType) = "world"
m = MyType(4)
println("hello $m")
println("hello " * string(m))
 

Вторая последняя строка вычисляется hello MyType(4) в REPL, в то время как последняя строка вычисляется (как и ожидалось) hello world .

Итак, что я делаю не так?

(Я все еще на версии 0.4, но официальные версии документов указывают, что это не должно иметь никакого значения.)

Ответ №1:

Документация совершенно правильная:

 julia> expand(:(println("hello $m")))
:(println((Base.string)("hello ",m)))
 

То println("hello $m") есть эквивалентно . println(string("hello", m)) К моменту компиляции или интерпретации кода это одно и то же.

Однако ваша перегрузка

 Base.string(m::MyType) = "world"
 

это неправильный способ перегрузки string . Этот метод охватывает случай только с одним аргументом типа MyType . (Вот почему, кстати, ваш код, похоже, работал для конкатенации: в этом конкретном примере использовался вызов string одного аргумента. Результаты были бы такими же, если бы вы написали "$m" .) Правильный способ его перегрузки

 Base.show(io::IO, m::MyType) = print(io, "world")
 

на первый взгляд это может показаться странным. Причина, по которой это должно быть перегружено, заключается string print в том, что делегаты делегируют show .

После обновления вашего минимального рабочего примера до

 type MyType
    x::Int
end
Base.show(io::IO, m::MyType) = print(io, "world")
m = MyType(4)
println("hello $m")
println("hello " * string(m))
 

результат, как и ожидалось.


В качестве сноски обратите внимание, что ваш пример может быть более эффективно записан как

 println("hello ", m)
 

что позволяет избежать создания промежуточных строк. Это иллюстрирует, почему система настроена так, что string вызовы print which calls show : метод ввода-вывода является более общим и может печатать в различные формы ввода-вывода напрямую, тогда как если бы все было наоборот, нужно было бы преобразовать вещи в строки (требующие временного выделения и, следовательно, низкой производительности) перед отправкой в IO.

Комментарии:

1. Отличный ответ! Действительно хорошо объяснено. Один быстрый вопрос: я уже сталкивался с этим раньше (я перегружал Base.< вместо перегрузки Base.isless ), поэтому мне было интересно, есть ли у вас какие-либо советы, чтобы узнать, какие функции следует перегружать? Есть ли ресурс, который показывает, какие функции находятся в «нижней части цепочки»?

2. ps Я мог бы сделать это отдельным вопросом StackOverflow, если ответ вообще длинный. Дайте мне знать, и я это сделаю…

3. Честно говоря, я не знаю ответа. Я лично не знаю о таком ресурсе. Было бы неплохо иметь.

4. Не беспокойтесь. Спасибо за ответ. Я мог бы опубликовать что-нибудь для пользователей julia по этому поводу.

5. Что касается < vs isless . , лучше перегрузить isless . Ресурс, используемый для обнаружения этого, находится @edit 1>3 в REPL, который попадает в код и показывает резервный isless вариант .